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。,当然这是我的猜想哈,不过应该可行。

  • 相关阅读:
    Laravel 初始化
    ant design pro 左上角 logo 修改
    请求到服务端后是怎么处理的
    Websocket 知识点
    王道数据结构 (7) KMP 算法
    王道数据结构 (6) 简单的模式匹配算法
    王道数据结构 (4) 单链表 删除节点
    王道数据结构 (3) 单链表 插入节点
    王道数据结构 (2) 单链表 尾插法
    王道数据结构 (1) 单链表 头插法
  • 原文地址:https://www.cnblogs.com/zhiyong-ITNote/p/7231590.html
Copyright © 2011-2022 走看看