当前位置: 代码迷 >> ASP >> 在 ASP.NET 中,怎么巧用 HttpModule ,以实现系统全局登录逻辑判断,高手慎入
  详细解决方案

在 ASP.NET 中,怎么巧用 HttpModule ,以实现系统全局登录逻辑判断,高手慎入

热度:447   发布时间:2012-11-06 14:07:00.0
在 ASP.NET 中,如何巧用 HttpModule ,以实现系统全局登录逻辑判断,高手慎入

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