几乎每个系统都要登录,我看过一些系统直接在每个页面的 Page_Load 里面判断 if(session["user"] == null) ,来实现登录判断。我认为这样不好,维护性太差。
今天我要实现的就是系统全局登录逻辑判断。
还是直接贴代码了,代码能说明一切。
首先我们定义一个 SiteUser 类。
/// <summary> /// 本网站需要记录的信息 /// </summary> public class SiteUser { public int Id { get; set; } public string UserName { get; set; } public DateTime LoginTime { get; set; } }
?
然后定义个 PassportManager 类,用来维护客户端和服务器端的状态信息。
/// <summary> /// 系统账户管理,可以用 Session 或 Cookie 来管理 /// </summary> public class PassportManager { /// <summary> /// 记录当前用户的信息 /// </summary> /// <param name="siteUser"></param> public static void SaveSiteUser(HttpContext context, SiteUser siteUser) { if (context == null) { throw new ArgumentNullException("context"); } if (siteUser == null) { throw new ArgumentNullException("siteUser"); } if (context.Session == null) { throw new NotSupportedException("当前上下文的 Session 为 Null,无法记录用户信息!"); } context.Session["currentUser"] = siteUser; } /// <summary> /// 得到账户,如果为空或已经过期,则返回 null /// </summary> /// <param name="context">当前请求的上下文</param> /// <returns></returns> public static SiteUser GetPassport(HttpContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (context.Session == null) { throw new NotSupportedException("当前上下文的 Session 为 Null,无法获取用户信息!"); } return (SiteUser)context.Session["currentUser"]; } /// <summary> /// 注销账户 /// </summary> /// <param name="context">当前请求的上下文</param> public static void PassportLogout(HttpContext context) { if (context == null) { throw new ArgumentNullException("context"); } context.Session.Clear(); context.Session.Abandon(); } }
然后我们定义一个 IPublicPage 空接口,你可能好奇为什么是空接口呢?因为空接口已经足够满足我们的要求。
/// <summary> /// 实现该空接口,就表示该页面无须登录 /// </summary> public interface IPublicPage { }
然后我们建立一个 passport-login.aspx 页面,用来登录。这里由于是演示,我们就不用访问数据库了。
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <h1>欢迎来到登录页面</h1> </div> <div> 登录名:<asp:TextBox ID="txtLoginName" runat="server" Width="300px"> </asp:TextBox><br /><br /> 密码:<asp:TextBox ID="txtLoginPassword" runat="server" TextMode="Password" Width="300px"> </asp:TextBox> <br /><br /> <asp:Button ID="btnLogin" runat="server" Text="登录" OnClick="btnLogin_Click" /> <a href="Index.aspx">回首页</a> </div> </form> </body> </html>
passport-login.aspx 的后台代码如下:
public partial class passport_login : System.Web.UI.Page, IPublicPage { protected void Page_Load(object sender, EventArgs e) { } protected void btnLogin_Click(object sender, EventArgs e) { string userName = this.txtLoginName.Text; string userPassword = this.txtLoginPassword.Text; SiteUser user = new SiteUser() { Id = 1, UserName = userName, LoginTime = DateTime.Now }; PassportManager.SaveSiteUser(Context, user); Response.Redirect("Index.aspx"); } }
Index.aspx 页面很简单,代码如下:
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <h1>欢迎来到本网站</h1> </div> <div> 欢迎您,<asp:Literal ID="ltLoginName" runat="server" /> 登录时间:<asp:Literal ID="ltLoginTime" runat="server" /> </div> </form> </body> </html>
?
Index.aspx 的后台代码也很简单,请注意,它没有像?passport-login.aspx 那样实现 IPublicPage,因为它需要登录。
public partial class Index : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if(!IsPostBack) { InitData(); } } protected void InitData() { SiteUser siteUser = PassportManager.GetPassport(Context); this.ltLoginName.Text = siteUser.UserName; this.ltLoginTime.Text = siteUser.LoginTime.ToString("yyyy-MM-dd HH:mm:ss"); } }
最后,这也是核心部分,新建一个 LoginModule 类,实现 IHttpModule
public class LoginModule : IHttpModule { public void Dispose() { } public void Init(HttpApplication context) { context.AcquireRequestState += new EventHandler(context_AcquireRequestState); } private void context_AcquireRequestState(object sender, EventArgs e) { HttpContext context = ((HttpApplication)sender).Context; if(context.Handler is IRequiresSessionState && !(context.Handler is IPublicPage)) { //需要登录,才能访问 SiteUser user = PassportManager.GetPassport(context); if (user == null) { context.Response.Redirect("passport-login.aspx?returnUrl=" + HttpUtility.UrlEncode(context.Request.RawUrl)); } } } }
最后在 Web.Config 文件中注册一下。
<system.web> <httpModules> <add name="LoginModule" type="PrivilegeDemo.WebUI.Code.LoginModule"/> </httpModules> </system.web>
?
最后运行,访问 Index.aspx 页面,成功跳到了 passport-login.aspx 页面,随便输入一个用户名和密码后,点击登录,跳回 Index.aspx,成功!