代码改变世界

(原创)在 ASP.NET 中,如何巧用 HttpModule ,以实现系统全局登录逻辑判断,高手慎入

2012-03-04 01:49  音乐让我说  阅读(4383)  评论(46编辑  收藏  举报

今晚写代码,即使现在已经 1: 27 了,依旧充满了激情。

几乎每个系统都要登录,我看过一些系统直接在每个页面的 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" />
&nbsp;&nbsp;&nbsp;
<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" />
&nbsp;&nbsp;&nbsp;
登录时间:<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,成功!

 

Demo 下载:https://files.cnblogs.com/Music/PrivilegeDemo.rar

谢谢浏览!