zoukankan      html  css  js  c++  java
  • ASP.NET底层封装HttpModule实例---FormsAuthentication类的分析

    HttpModule是用来注册HttpApplication事件的,实现IHttpModule接口的托管代码模块可以访问该请求管道的所有事件。那么对于我们最常用的ASP.NET Forms身份验证模块是如何底层封装处理的呢?

    今天过了一遍ASP.NET生命周期,以前的时候喜欢做各种应用,小程序等,渐渐地就觉得真没意思,因为只要你懂点基本的语法,会用相关的库亦或是框架就行,如果出错就是些许的细节错误,严格来说这不锻炼人,这有点像是温水煮青蛙,当然不能说这不好,这可以帮我们熟练地掌握框架的使用,增加熟练度及相关基础的应用,但是就个人而言老觉得缺点什么...后来想想,我要做的其实就是让别人用我开发的框架,库,我想研究的是框架底层的架构而不是用框架。于是过了一遍生命周期,处了IIS处理请求部分实在不懂之外,对ASP.NET处理请求还是更熟练了,对于不懂得我不会去刻意强求懂,毕竟自己的技术深度,广度摆在那,日后到了时候自然会懂。IIS7较之于之前的版本,其扩增了一个集成模式。IS 7.0 集成管道是一种统一的请求处理管道,它同时支持本机代码和托管代码模块。实现 IHttpModule 接口的托管代码模块可访问该请求管道中的所有事件。例如,托管代码模块可用于 ASP.NET 网页(.aspx 文件)和 HTML 页(.htm 或 .html 文件)的 ASP.NET Forms 身份验证。即使 IIS 和 ASP.NET 将 HTML 页视为静态资源,情况也是如此。

    从功能上讲,HttpModule之于ASP.NET,就好比ISAPI Filter之于IIS一样。IIS将接收到的请求分发给相应的ISAPI Extension之前,注册的ISAPI Filter会先截获该请求。ISAPI Filter可以获取甚至修改请求的内容,完成一些额外的功能。与之相似地,当请求转入ASP.NET管道后,最终负责处理该请求的是与请求资源类型相匹配的HttpHandler对象,但是在Handler正式工作之前,ASP.NET会先加载并初始化所有配置的HttpModule对象。HttpModule在初始化的过程中,会将一些功能注册到HttpApplication相应的事件中,那么在HttpApplication整个请求处理生命周期中的某个阶段,相应的事件会被触发,通过HttpModule注册的事件处理程序也得以执行。

    所有的HttpModule都实现了IHttpModule接口,下面是IHttpModule的定义。其中Init方法用于实现HttpModule自身的初始化,该方法接受一个HttpApplication对象,有了这个对象,事件注册就很容易了。

    ASP.NET提供的很多基础构件(Infrastructure)功能都是通过相应的HttpModule实现的,下面类列出了一些典型的HttpModule:

        OutputCacheModule:实现了输出缓存(Output Caching)的功能;
        SessionStateModule:在无状态的HTTP协议上实现了基于会话(Session)的状态;
        WindowsAuthenticationModule + FormsAuthenticationModule + PassportAuthentication- Module:实现了3种典型的身份认证方式:Windows认证、Forms认证和Passport认证;
        UrlAuthorizationModule + FileAuthorizationModule:实现了基于Uri和文件ACL(Access Control List)的授权。

    抱着吹毛求疵的学习态度,我研究了一下Forms认证的源码(其实也不是源码,利用reflector查出来的)

    看下FormsAuthenticationModule的源码:

    看下我们最熟的Init方法:

    可以看到,在这里给我们注册了两个HttpApplication管道事件,我们看看AuthenticateRequest事件给我们的解释:

    然后我们看看OnEnter这个方法:

    随后我们点进去看看OnAuthenticate方法:

      private void OnAuthenticate(FormsAuthenticationEventArgs e)
    {
        HttpCookie cookie = null;
        if (this._eventHandler != null)
        {
            this._eventHandler(this, e);
        }
        if (e.Context.User == null)
        {
            if (e.User != null)
            {
                e.Context.SetPrincipalNoDemand(e.User);
            }
            else
            {
                bool cookielessTicket = false;
                FormsAuthenticationTicket tOld = ExtractTicketFromCookie(e.Context, FormsAuthentication.FormsCookieName, out cookielessTicket);
                if ((tOld != null) && !tOld.Expired)
                {
                    FormsAuthenticationTicket ticket = tOld;
                    if (FormsAuthentication.SlidingExpiration)
                    {
                        ticket = FormsAuthentication.RenewTicketIfOld(tOld);
                    }
                    e.Context.SetPrincipalNoDemand(new GenericPrincipal(new FormsIdentity(ticket), new string[0]));
                    if (!cookielessTicket && !ticket.CookiePath.Equals("/"))
                    {
                        cookie = e.Context.Request.Cookies[FormsAuthentication.FormsCookieName];
                        if (cookie != null)
                        {
                            cookie.Path = ticket.CookiePath;
                        }
                    }
                    if (ticket != tOld)
                    {
                        if ((cookielessTicket && (ticket.CookiePath != "/")) && (ticket.CookiePath.Length > 1))
                        {
                            ticket = FormsAuthenticationTicket.FromUtc(ticket.Version, ticket.Name, ticket.IssueDateUtc, ticket.ExpirationUtc, ticket.IsPersistent, ticket.UserData, "/");
                        }
                        string cookieValue = FormsAuthentication.Encrypt(ticket, !cookielessTicket);
                        if (cookielessTicket)
                        {
                            e.Context.CookielessHelper.SetCookieValue('F', cookieValue);
                            e.Context.Response.Redirect(e.Context.Request.RawUrl);
                        }
                        else
                        {
                            if (cookie != null)
                            {
                                cookie = e.Context.Request.Cookies[FormsAuthentication.FormsCookieName];
                            }
                            if (cookie == null)
                            {
                                cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue) {
                                    Path = ticket.CookiePath
                                };
                            }
                            if (ticket.IsPersistent)
                            {
                                cookie.Expires = ticket.Expiration;
                            }
                            cookie.Value = cookieValue;
                            cookie.Secure = FormsAuthentication.RequireSSL;
                            cookie.HttpOnly = true;
                            if (FormsAuthentication.CookieDomain != null)
                            {
                                cookie.Domain = FormsAuthentication.CookieDomain;
                            }
                            e.Context.Response.Cookies.Remove(cookie.Name);
                            e.Context.Response.Cookies.Add(cookie);
                        }
                    }
                }
            }
        }
    }

    留心的话,可以发现在这个方法里面所有与Forms表单认证相关的类都涉及到了。因此对于Forms表单认证的处理模块,最重要的就是这个FormsAuthenticationModule类了,在这里面,会把为了解耦操作所创建的类都给用上。不得不说,要我写写不出来,理解下HttpModule管道的实际应用还是可以的,对模块设计有个大概的了解。在这里,这个类不知道会不会让你想起ASP.NET MVC框架下的Authentication Filter这个过滤器,过滤器的实现其实就是利用了Attribute这个特性才实现AOP切面注入,因此,其实这个也应该可以加上Attribute来实现AOP。,当然这是我的猜想哈,不过应该可行。

  • 相关阅读:
    2020-09-05:虚拟内存知道么?什么时候使用虚拟内存?虚拟内存除了扩大内存还有什么用?
    2020-09-04:函数调用约定了解么?
    2020-09-03:裸写算法:回形矩阵遍历。
    2020-09-02:Sqoop的工作原理?
    2020-09-01:mysql里什么是检查点、保存点和中间点?
    2020-08-31:描述HTTP的版本之间的区别,主要是1.0/1.1/2.0三个版本的区别。
    2020-08-30:裸写算法:二叉树两个节点的最近公共祖先。
    2020-08-29:进程线程的区别,除了包含关系之外的一些区别,底层详细信息?
    2020-08-28:边缘网关协议了解么?简单描述一下。
    2020-08-27:OpenStack与Docker的区别?
  • 原文地址:https://www.cnblogs.com/zhiyong-ITNote/p/7231590.html
Copyright © 2011-2022 走看看