ASP.NET底層封裝HttpModule實例---FormsAuthentication類的分析

来源:http://www.cnblogs.com/zhiyong-ITNote/archive/2017/07/24/7231590.html
-Advertisement-
Play Games

HttpModule是用來註冊HttpApplication事件的,實現IHttpModule介面的托管代碼模塊可以訪問該請求管道的所有事件。那麼對於我們最常用的ASP.NET Forms身份驗證模塊是如何底層封裝處理的呢? ...


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。,當然這是我的猜想哈,不過應該可行。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1:項目場景 在設計數據表的時候有時候為了將來統計或查詢的方便,我們會冗餘一些欄位。如有三張數據表,學校信息表、班級動態表、班級信息表。 班級動態由學校老師所發,可以進行評論點贊等操作,為了提升這種非結構化數據的訪問效率,存儲於Mongodb中,冗餘了學校名稱欄位,假設班級表也冗餘了學校名稱欄位。而 ...
  • 1. 卓聘IM開發背景 智聯卓聘是智聯旗下高端人才招聘平臺,成立快4年了,業務增漲每年以100%速度增漲,業務增漲快在開發和上線速度要求也比較高。 2016年6月提出IM開發需求,7月初上線,開發人員三名,開發時間20多天,後期可以不斷滿足業務需求。前期階段我們考慮網上各種提供IM的雲平臺,這些平臺 ...
  • 本文出處:http://www.cnblogs.com/wy123/p/7218316.html (保留出處並非什麼原創作品權利,本人拙作還遠遠達不到,僅僅是為了鏈接到原文,因為後續對可能存在的一些錯誤進行修正或補充,無他) 資料庫中的事物是具有原子性(Atomicity),一致性(Consiste ...
  • 本文通過示例詳細分析rsync演算法原理和rsync的工作流程,是對rsync官方技術報告和官方推薦文章的解釋。 以下是rsync系列篇: 1.rsync(一):基本命令和用法 2.rsync(二):inotify+rsync詳細說明和sersync 3.rsync演算法原理和工作流程分析 4.rsyn ...
  • 文本文件的操作 #輸入重定向 tr 'a-z' 'A-Z' hello HELLO world WORLD 重定向後 tr 'a-z' 'A-Z' < file HELLO WORLD #格式化輸入內容到文件: #標準輸入、標準輸出與標準錯誤 標準輸入0(鍵盤僅讀取)、標準輸出1與標準錯誤2(顯示屏 ...
  • 隨著網站業務越來越複雜,對數據存儲和檢索的需求也越來越複雜,網站需要採用一些非關係型資料庫技術(即NoSQL)和非資料庫查詢技術如搜索引擎。NoSQL資料庫一般使用MongoDb,搜索引擎一般使用ElasticSearch,最好可以研究ELK整套解決方案。 使用NoSQL和搜索引擎 NoSQL和搜索 ...
  • 在你的項目屬性頁面裡面,把是否包含unsafe代碼的選項選上 ...
  • 我色盲,不是真色盲,而是對顏色沒感覺,配出來太醜了,找了找配色表,發現是網頁的,每次都要開瀏覽器 就自己做了個,panel + text ,純界面操作,沒有代碼,調調色,填填文字什麼的 下載地址:pan.baidu.com/s/1qYTtaHI ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...