亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

[ASP.NET MVC] 利用自定義的AuthenticationFilt

系統 3931 0
原文: [ASP.NET MVC] 利用自定義的AuthenticationFilter實現Basic認證

很多情況下目標Action方法都要求在一個安全上下文中被執行,這里所謂的安全上下文主要指的是當前請求者是一個經過授權的用戶。授權的本質就是讓用戶在他許可的權限范圍內做他能夠做的事情,授權的前提是請求者是一個經過認證的用戶。質詢-應答(Chanllenge-Response)”是用戶認證采用的一種常用的形式,認證方向被認證方發出質詢以要求其提供用于實施認證的用戶憑證,而被認證方提供相應的憑證以作為對質詢的應答。旨在目標Action方法執行之前實施身分認證的AuthenticationFilter也對這種認證方法提供了支持。

一、IAuthenticationFilter接口

所有的AuthenticationFilter類型均實現了IAuthenticationFilter接口,該接口定義在命名空間“System.Web.Mvc.Filters”下(其他四種過濾器接口都定義在“System.Web.Mvc”命名空間下)。如下面的代碼片斷所示,OnAuthentication和OnAuthenticationChallenge這兩個方法被定義在此接口中,前者用于對請求實施認證,后者則負責將相應的認證質詢發送給請求者。

        
             1:
        
        
          public
        
        
          interface
        
         IAuthenticationFilter
      
        
             2:
        
         {
      
        
             3:
        
        
          void
        
         OnAuthentication(AuthenticationContext filterContext);
      
        
             4:
        
        
          void
        
         OnAuthenticationChallenge(AuthenticationChallengeContext filterContext);
      
        
             5:
        
         }
      

定義在IAuthenticationFilter接口的兩個方法都將一個上下文對象作為其唯一參數。OnAuthentication方法的這個參數類型為AuthenticationContext,如下面的代碼片斷所示,它是ControllerContext的子類。AuthenticationContext的ActionDescriptor返回的自然是用于描述目標Action方法的ActionDescriptor對象。借助于Principal屬性,我們可以獲取或設置代表當前用戶的Principal對象。如果我們在執行OnAuthentication方法的過程中設置了AuthenticationContext的Result屬性,提供的ActionResult將直接用于響應當前請求。

        
             1:
        
        
          public
        
        
          class
        
         ActionExecutingContext : ControllerContext
      
        
             2:
        
         {    
      
        
             3:
        
        
          public
        
         ActionExecutingContext();
      
        
             4:
        
        
          public
        
         ActionExecutingContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor,IDictionary<
        
          string
        
        , 
        
          object
        
        > actionParameters);
      
        
             5:
        
        ? 
      
        
             6:
        
        
          public
        
        
          virtual
        
         ActionDescriptor             ActionDescriptor { get; set; }
      
        
             7:
        
        
          public
        
        
          virtual
        
         IDictionary<
        
          string
        
        , 
        
          object
        
        >  ActionParameters { get; set; }
      
        
             8:
        
        
          public
        
         ActionResult                         Result { get; set; }
      
        
             9:
        
         }
      

OnAuthenticationChallenge方法的參數類型為AuthenticationChallengeContext。如下面的代碼片斷所示,它依然是ControllerContext的子類。它同樣具有一個用于描述目標Action方法的ActionDescriptor屬性,其Result屬性代表的ActionResult對象將用于響應當前請求。

        
             1:
        
        
          public
        
        
          class
        
         ActionExecutedContext : ControllerContext
      
        
             2:
        
         {    
      
        
             3:
        
        
          public
        
         ActionExecutedContext();   
      
        
             4:
        
        
          public
        
         ActionExecutedContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor, 
        
          bool
        
         canceled, Exception exception);
      
        
             5:
        
        ? 
      
        
             6:
        
        
          public
        
        
          virtual
        
         ActionDescriptor     ActionDescriptor { get; set; }
      
        
             7:
        
        
          public
        
        
          virtual
        
        
          bool
        
                         Canceled { get; set; }
      
        
             8:
        
        
          public
        
        
          virtual
        
         Exception            Exception { get; set; }
      
        
             9:
        
        
          public
        
        
          bool
        
                                 ExceptionHandled { get; set; }
      
        
            10:
        
        
          public
        
         ActionResult                 Result { get; set; }
      
        
            11:
        
         }
      

二、AuthenticationFilter的執行流程

我們知道身份認證總是對請求處理的第一個步驟,因為只有確定了請求者的真實身份,安全才能得到保障,所以AuthenticationFilter是最先被執行的一類過濾器。所有過濾器的執行都是ActionInvoker來驅動的,ASP.NET MVC在默認情況下采用的ActionInvoker是一個AsyncControllerActionInvoker對象,后者類型派生于ControllerActionInvoker。ControllerActionInvoker針對AuthenticationFilter的執行體現在如下兩個方法(InvokeAuthenticationFilters和InvokeAuthenticationFiltersChallenge)上。

        
             1:
        
        
          public
        
        
          class
        
         ControllerActionInvoker : IActionInvoker
      
        
             2:
        
         {
      
        
             3:
        
        
          //其他成員
        
      
        
             4:
        
        
          protected
        
        
          virtual
        
         AuthenticationContext InvokeAuthenticationFilters(ControllerContext controllerContext,IList<IAuthenticationFilter> filters, ActionDescriptor actionDescriptor);
      
        
             5:
        
        
          protected
        
        
          virtual
        
         AuthenticationChallengeContext InvokeAuthenticationFiltersChallenge(ControllerContext controllerContext, IList<IAuthenticationFilter> filters, ActionDescriptor actionDescriptor, ActionResult result);   
      
        
             6:
        
         }
      
如果多個AuthenticationFilter同時被應用到目標Action方法上,ControllerActionInvoker會根據對應Filter的Order/Scope屬性對它們進行排序。隨后ControllerActionInvoker會根據當前ControllerContext、描述目標Action方法的ActionDescriptor對象以及原始的Principal(對應于當前HttpContext的User屬性)創建一個AuthenticationContext對象,并以此作為參數以此調用每個AuthenticationFilter對象的OnAuthentication對象實施認證。

在目標Action方法被執行之后,通過本書第11章“View的呈現”我們知道最終執行的結果會被封裝為一個ActionResult對象。ControllerActionInvoker會利用當前ControllerContext、描述目標Action方法的ActionDescriptor對象和這個ActionResult創建一個AuthenticationChallengeContext對象,并將其作為參數依次調用每個AuthenticationFilter的OnAuthenticationChallenge方法。這個AuthenticationChallengeContext對象的Result屬性最終返回的ActionResult對象將被用來對請求予以響應。

右圖基本反映了整個“AuthenticationFilter鏈”的執行流程, 但是如果在執行某個AuthenticationFilter對象的OnAuthenticatio方法時對作為參數的AuthenticationContext對象的Result屬性作了相應的設置,針對整個“AuthenticationFilter鏈”的執行將會立即中止,指定的這個ActionResult對象將用于響應當前請求 。如果在執行過程中對AuthenticationContext對象的Principal屬性作了相應的設置,該屬性值將會作為當前HttpContext和當前線程的Principal。

三、實例演示:通過自定義AuthenticationFilter實現Basic認證

在ASP.NET MVC的應用編程接口中,我們找不到IAuthenticationFilter接口的實現者。為了讓大家對這個在ASP.NET MVC 5才引入的過濾器具有更加深刻的認識,我們接下來會通過一個實例來演示如何通過自定義的AuthenticationFilter實現針對Basic方案的認證。不過在這之前,我們有必要對Basic這種基本的認證方法作一個基本的了解。Basic和Digest是兩種典型的HTTP認證方案。對于前者,雖然客戶端提供的認證憑證(用戶名+密碼)僅僅是被Base64編碼而沒有被加密,但是我們可以通過采用HTTPS傳輸利用SSL來解決機密性的問題,所以Basic認證也不失為一種不錯的認證方案。左圖體現了Basic認證的基本流程,可以看出這也是一種典型的采用“質詢-應答”模式的認證方案,整個流程包含如下兩個基本步驟。

  • 客戶端向服務端發送一個HTTP請求,服務端返回一個狀態為“401, Unauthorized”的響應。該響應具有一個“WWW-Authenticate”的報頭標明采用的是Basic認證方案。Basic認證是在一個“領域(Realm)”限定的上下文中進行的,該報頭還可以執行認證的領域,左圖所示的WWW-Authenticate報頭值為:Basic realm="localhost"。
  • · 客戶端向服務端發送一個攜帶基于用戶名/密碼的認證憑證的請求。認證憑證的格式為“{UserName}:{Password}”,并采用Base64編碼(編碼的目的不是為了保護提供的密碼)。這樣一個經過編碼的認證憑證被存放在請求報頭Authorization中,相應的認證方案類型(Basic)依然需要在該報頭中指定,左圖所示的Authorization報頭值為:Basic YcdfaYsss==。服務端接收到請求之后,從Authorization報頭中提取憑證并對其進行解碼,最后采用提取的用戶名和密碼實施認證。認證成功之后,該請求會得到正常的處理,并回復一個正常的響應。

在正式介紹如果定義這個實現Basic認證的AuthenticationFilter之前,我們不妨先來看看使用了這個自定義AuthenticationFilter會產生怎樣的效果。我們在一個ASP.NET MVC應用中定義了如下一個HomeController,定義其中的默認Action方法Index會輸出以三種形式體現的“當前用戶名”。HomeController類型上應用的AuthenticateAttribute特性正是我們自定義的AuthenticationFilter。

        
             1:
        
        
           [Authenticate]
        
      
        
             2:
        
        
          public
        
        
          class
        
         HomeController : Controller
      
        
             3:
        
         {
      
        
             4:
        
        
          public
        
        
          void
        
         Index()
      
        
             5:
        
             {
      
        
             6:
        
                 Response.Write(
        
          string
        
        .Format(
        
          "Controller.User: {0}<br/>"
        
        , 
        
          this
        
        .User.Identity.Name));
      
        
             7:
        
                 Response.Write(
        
          string
        
        .Format(
        
          "HttpContext.User: {0}<br/>"
        
        , 
        
          this
        
        .ControllerContext.HttpContext.User.Identity.Name));
      
        
             8:
        
                 Response.Write(
        
          string
        
        .Format(
        
          "Thread.CurrentPrincipal: {0}"
        
        , Thread.CurrentPrincipal.Identity.Name));
      
        
             9:
        
             }
      
        
            10:
        
         }
      

由于瀏覽器默認提供對Basic認證的支持,所以當我們運行該程序后如下圖所示的登錄對話框會自動彈出,當我們輸入正確的用戶名和密碼(用戶名和密碼直接維護在AuthenticateAttribute上)后,當前登錄用戶名會呈現在瀏覽器上。

這個用于實現Basic認證的AuthenticateAttribute定義如下,簡單起見我們將帳號采用的用戶名和密碼保存在一個靜態字段中。具體的認證實現在實現的OnAuthentication方法中,我們在該方法中調用IsAuthenticated判斷請是否經過認證,并在認證成功的情況下得到代表請求用戶的Principal對象,然對作為參數的AuthenticationContext對象的Principal屬性進行賦值。對于沒有經過認證的請求,我們會調用另一個方法ProcessUnauthenticatedRequest對其進行處理。

        
             1:
        
        
          public
        
        
          class
        
         AuthenticateAttribute:FilterAttribute,IAuthenticationFilter
      
        
             2:
        
         {
      
        
             3:
        
        
          public
        
        
          const
        
        
          string
        
         AuthorizationHeaderName           =
        
          "Authorization"
        
        ;
      
        
             4:
        
        
          public
        
        
          const
        
        
          string
        
         WwwAuthenticationHeaderName       =
        
          "WWW-Authenticate"
        
        ;
      
        
             5:
        
        
          public
        
        
          const
        
        
          string
        
         BasicAuthenticationScheme         =
        
          "Basic"
        
        ;
      
        
             6:
        
        
          private
        
        
          static
        
         Dictionary<
        
          string
        
        , 
        
          string
        
        > userAccounters;
      
        
             7:
        
        ? 
      
        
             8:
        
        
          static
        
         AuthenticateAttribute()
      
        
             9:
        
             {
      
        
            10:
        
                 userAccounters = 
        
          new
        
         Dictionary<
        
          string
        
        , 
        
          string
        
        >(StringComparer.OrdinalIgnoreCase);
      
        
            11:
        
        ? 
      
        
            12:
        
                 userAccounters.Add(
        
          "Foo"
        
        , 
        
          "Password"
        
        );
      
        
            13:
        
                 userAccounters.Add(
        
          "Bar"
        
        , 
        
          "Password"
        
        );
      
        
            14:
        
                 userAccounters.Add(
        
          "Baz"
        
        , 
        
          "Password"
        
        );
      
        
            15:
        
             }
      
        
            16:
        
        ? 
      
        
            17:
        
        
          public
        
        
          void
        
         OnAuthentication(AuthenticationContext filterContext)
      
        
            18:
        
             {
      
        
            19:
        
                 IPrincipal user;
      
        
            20:
        
        
          if
        
         (
        
          this
        
        .IsAuthenticated(filterContext, 
        
          out
        
         user))
      
        
            21:
        
                 {
      
        
            22:
        
                     filterContext.Principal = user;
      
        
            23:
        
                 }
      
        
            24:
        
        
          else
        
      
        
            25:
        
                 {
      
        
            26:
        
        
          this
        
        .ProcessUnauthenticatedRequest(filterContext);
      
        
            27:
        
                 }
      
        
            28:
        
             }
      
        
            29:
        
        ? 
      
        
            30:
        
        
          protected
        
        
          virtual
        
         AuthenticationHeaderValue GetAuthenticationHeaderValue(AuthenticationContext filterContext)
      
        
            31:
        
             {
      
        
            32:
        
        
          string
        
         rawValue = filterContext.RequestContext.HttpContext.Request.Headers[AuthorizationHeaderName];
      
        
            33:
        
        
          if
        
         (
        
          string
        
        .IsNullOrEmpty(rawValue))
      
        
            34:
        
                 {
      
        
            35:
        
        
          return
        
        
          null
        
        ;
      
        
            36:
        
                 }
      
        
            37:
        
        
          string
        
        [] split = rawValue.Split(
        
          ' '
        
        );
      
        
            38:
        
        
          if
        
         (split.Length != 2)
      
        
            39:
        
                 {
      
        
            40:
        
        
          return
        
        
          null
        
        ;
      
        
            41:
        
                 }
      
        
            42:
        
        
          return
        
        
          new
        
         AuthenticationHeaderValue(split[0], split[1]);
      
        
            43:
        
             }
      
        
            44:
        
        ? 
      
        
            45:
        
        
          protected
        
        
          virtual
        
        
          bool
        
         IsAuthenticated(AuthenticationContext filterContext, 
        
          out
        
         IPrincipal user)
      
        
            46:
        
             {
      
        
            47:
        
                 user = filterContext.Principal;
      
        
            48:
        
        
          if
        
         (
        
          null
        
         != user & user.Identity.IsAuthenticated)
      
        
            49:
        
                 {
      
        
            50:
        
        
          return
        
        
          true
        
        ;
      
        
            51:
        
                 }
      
        
            52:
        
        ? 
      
        
            53:
        
                 AuthenticationHeaderValue token = 
        
          this
        
        .GetAuthenticationHeaderValue(filterContext);
      
        
            54:
        
        
          if
        
         (
        
          null
        
         != token && token.Scheme ==  BasicAuthenticationScheme)
      
        
            55:
        
                 {
      
        
            56:
        
        
          string
        
         credential = Encoding.Default.GetString(Convert.FromBase64String(token.Parameter));
      
        
            57:
        
        
          string
        
        [] split = credential.Split(
        
          ':'
        
        );
      
        
            58:
        
        
          if
        
         (split.Length == 2)
      
        
            59:
        
                     {
      
        
            60:
        
        
          string
        
         userName = split[0];
      
        
            61:
        
        
          string
        
         password;
      
        
            62:
        
        
          if
        
         (userAccounters.TryGetValue(userName, 
        
          out
        
         password))
      
        
            63:
        
                         {
      
        
            64:
        
        
          if
        
         (password == split[1])
      
        
            65:
        
                             {
      
        
            66:
        
                                 GenericIdentity identity = 
        
          new
        
         GenericIdentity(userName);
      
        
            67:
        
                                 user = 
        
          new
        
         GenericPrincipal(identity, 
        
          new
        
        
          string
        
        [0]);
      
        
            68:
        
        
          return
        
        
          true
        
        ;
      
        
            69:
        
                             }
      
        
            70:
        
                         }
      
        
            71:
        
                     }
      
        
            72:
        
                 }
      
        
            73:
        
        
          return
        
        
          false
        
        ;
      
        
            74:
        
             }
      
        
            75:
        
        ? 
      
        
            76:
        
        
          protected
        
        
          virtual
        
        
          void
        
         ProcessUnauthenticatedRequest(AuthenticationContext filterContext)
      
        
            77:
        
             {
      
        
            78:
        
        
          string
        
         parameter = 
        
          string
        
        .Format(
        
          "realm=\"{0}\""
        
        , filterContext.RequestContext.HttpContext.Request.Url.DnsSafeHost);
      
        
            79:
        
                 AuthenticationHeaderValue challenge = 
        
          new
        
         AuthenticationHeaderValue(BasicAuthenticationScheme, parameter);
      
        
            80:
        
                 filterContext.HttpContext.Response.Headers[WwwAuthenticationHeaderName] = challenge.ToString();
      
        
            81:
        
                 filterContext.Result = 
        
          new
        
         HttpUnauthorizedResult();
      
        
            82:
        
             }
      
        
            83:
        
        ? 
      
        
            84:
        
        
          public
        
        
          void
        
         OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) {}
      
        
            85:
        
         }
      

在對請求實施認證的IsAuthenticated方法中,我們會試圖從請求的Authorization報頭中提取安全憑證,并按照Basic憑證的格式解析出用戶名和密碼。只有在用戶名和密碼匹配的情況下,我們認為請求通過認證,并根據解析出來的用戶名創建一個GenericPrincipal對象作為輸出參數user的值。如果請求并為通過認證(它可以是一個匿名請求,或者提供的用戶名與密碼不匹配),方法ProcessUnauthenticatedRequest會被調用。在此情況下,它會對響應的WWW-Authenticate報頭進行相應的設置,并創建一個HttpUnauthorizedResult對象作為AuthenticationContext對象的Result屬性,那么客戶端最終會接收到一個狀態為“401, Unauthorized”的響應。

[ASP.NET MVC] 利用自定義的AuthenticationFilter實現Basic認證


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 97在线观看成人免费视频 | 国产免费久久精品44 | 2019中文字幕视频 | 老师邪恶影院a啦啦啦影院 老师在办公室被躁到白浆 老湿机午夜影院 | 99爱网站 | 国产欧美日韩中文字幕 | 久久精品国产亚洲香蕉 | 午夜性爽视频男人的天堂在线 | 波多野结衣中文一区二区免费 | 免费看一级毛片欧美 | 两个人高清视频图片中文字幕 | 亚洲视频在线播放 | 天天干亚洲 | 久久有这有精品在线观看 | 四虎网址在线观看 | 在线观看男女爱视频网站 | 欧美人交性视频在线香蕉 | 成人午夜精品网站在线观看 | 一区二区三区在线观看视频 | 亚洲国产欧美91 | 国产精品视频久久久 | 国产成人午夜精品影院游乐网 | 四虎成人www国产精品 | 日日干夜夜爱 | 激情 婷婷 | 亚洲国产精品久久久久 | 亚洲精品在线播放视频 | 亚洲国产另类久久久精品小说 | 欧美日韩中文字幕一区二区高清 | 波多野结衣 一区二区 | 欧美色欧美亚洲高清在线观看 | 神马色片 | 久久国内精品自在自线400部o | 色综合天天综合高清网国产 | bbw下身丰满18ⅹxxⅹ | www.成人在线视频 | 成人在线视频观看 | 精品在线免费视频 | 九9热这里真品 | 成人小视频在线观看免费 | 99久久免费看国产精品 |