日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

[ASP.NET MVC] 利用自定义的AuthenticationFilter实现Basic认证

發(fā)布時(shí)間:2025/6/15 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [ASP.NET MVC] 利用自定义的AuthenticationFilter实现Basic认证 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

很多情況下目標(biāo)Action方法都要求在一個(gè)安全上下文中被執(zhí)行,這里所謂的安全上下文主要指的是當(dāng)前請(qǐng)求者是一個(gè)經(jīng)過(guò)授權(quán)的用戶(hù)。授權(quán)的本質(zhì)就是讓用戶(hù)在他許可的權(quán)限范圍內(nèi)做他能夠做的事情,授權(quán)的前提是請(qǐng)求者是一個(gè)經(jīng)過(guò)認(rèn)證的用戶(hù)。質(zhì)詢(xún)-應(yīng)答(Chanllenge-Response)”是用戶(hù)認(rèn)證采用的一種常用的形式,認(rèn)證方向被認(rèn)證方發(fā)出質(zhì)詢(xún)以要求其提供用于實(shí)施認(rèn)證的用戶(hù)憑證,而被認(rèn)證方提供相應(yīng)的憑證以作為對(duì)質(zhì)詢(xún)的應(yīng)答。旨在目標(biāo)Action方法執(zhí)行之前實(shí)施身分認(rèn)證的AuthenticationFilter也對(duì)這種認(rèn)證方法提供了支持。

一、IAuthenticationFilter接口

所有的AuthenticationFilter類(lèi)型均實(shí)現(xiàn)了IAuthenticationFilter接口,該接口定義在命名空間“System.Web.Mvc.Filters”下(其他四種過(guò)濾器接口都定義在“System.Web.Mvc”命名空間下)。如下面的代碼片斷所示,OnAuthentication和OnAuthenticationChallenge這兩個(gè)方法被定義在此接口中,前者用于對(duì)請(qǐng)求實(shí)施認(rèn)證,后者則負(fù)責(zé)將相應(yīng)的認(rèn)證質(zhì)詢(xún)發(fā)送給請(qǐng)求者。

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

定義在IAuthenticationFilter接口的兩個(gè)方法都將一個(gè)上下文對(duì)象作為其唯一參數(shù)。OnAuthentication方法的這個(gè)參數(shù)類(lèi)型為AuthenticationContext,如下面的代碼片斷所示,它是ControllerContext的子類(lèi)。AuthenticationContext的ActionDescriptor返回的自然是用于描述目標(biāo)Action方法的ActionDescriptor對(duì)象。借助于Principal屬性,我們可以獲取或設(shè)置代表當(dāng)前用戶(hù)的Principal對(duì)象。如果我們?cè)趫?zhí)行OnAuthentication方法的過(guò)程中設(shè)置了AuthenticationContext的Result屬性,提供的ActionResult將直接用于響應(yīng)當(dāng)前請(qǐng)求。

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方法的參數(shù)類(lèi)型為AuthenticationChallengeContext。如下面的代碼片斷所示,它依然是ControllerContext的子類(lèi)。它同樣具有一個(gè)用于描述目標(biāo)Action方法的ActionDescriptor屬性,其Result屬性代表的ActionResult對(duì)象將用于響應(yīng)當(dāng)前請(qǐng)求。

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的執(zhí)行流程

我們知道身份認(rèn)證總是對(duì)請(qǐng)求處理的第一個(gè)步驟,因?yàn)橹挥写_定了請(qǐng)求者的真實(shí)身份,安全才能得到保障,所以AuthenticationFilter是最先被執(zhí)行的一類(lèi)過(guò)濾器。所有過(guò)濾器的執(zhí)行都是ActionInvoker來(lái)驅(qū)動(dòng)的,ASP.NET MVC在默認(rèn)情況下采用的ActionInvoker是一個(gè)AsyncControllerActionInvoker對(duì)象,后者類(lèi)型派生于ControllerActionInvoker。ControllerActionInvoker針對(duì)AuthenticationFilter的執(zhí)行體現(xiàn)在如下兩個(gè)方法(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: } 如果多個(gè)AuthenticationFilter同時(shí)被應(yīng)用到目標(biāo)Action方法上,ControllerActionInvoker會(huì)根據(jù)對(duì)應(yīng)Filter的Order/Scope屬性對(duì)它們進(jìn)行排序。隨后ControllerActionInvoker會(huì)根據(jù)當(dāng)前ControllerContext、描述目標(biāo)Action方法的ActionDescriptor對(duì)象以及原始的Principal(對(duì)應(yīng)于當(dāng)前HttpContext的User屬性)創(chuàng)建一個(gè)AuthenticationContext對(duì)象,并以此作為參數(shù)以此調(diào)用每個(gè)AuthenticationFilter對(duì)象的OnAuthentication對(duì)象實(shí)施認(rèn)證。

在目標(biāo)Action方法被執(zhí)行之后,通過(guò)本書(shū)第11章“View的呈現(xiàn)”我們知道最終執(zhí)行的結(jié)果會(huì)被封裝為一個(gè)ActionResult對(duì)象。ControllerActionInvoker會(huì)利用當(dāng)前ControllerContext、描述目標(biāo)Action方法的ActionDescriptor對(duì)象和這個(gè)ActionResult創(chuàng)建一個(gè)AuthenticationChallengeContext對(duì)象,并將其作為參數(shù)依次調(diào)用每個(gè)AuthenticationFilter的OnAuthenticationChallenge方法。這個(gè)AuthenticationChallengeContext對(duì)象的Result屬性最終返回的ActionResult對(duì)象將被用來(lái)對(duì)請(qǐng)求予以響應(yīng)。

右圖基本反映了整個(gè)“AuthenticationFilter鏈”的執(zhí)行流程,但是如果在執(zhí)行某個(gè)AuthenticationFilter對(duì)象的OnAuthenticatio方法時(shí)對(duì)作為參數(shù)的AuthenticationContext對(duì)象的Result屬性作了相應(yīng)的設(shè)置,針對(duì)整個(gè)“AuthenticationFilter鏈”的執(zhí)行將會(huì)立即中止,指定的這個(gè)ActionResult對(duì)象將用于響應(yīng)當(dāng)前請(qǐng)求。如果在執(zhí)行過(guò)程中對(duì)AuthenticationContext對(duì)象的Principal屬性作了相應(yīng)的設(shè)置,該屬性值將會(huì)作為當(dāng)前HttpContext和當(dāng)前線(xiàn)程的Principal。

三、實(shí)例演示:通過(guò)自定義AuthenticationFilter實(shí)現(xiàn)Basic認(rèn)證

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

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

在正式介紹如果定義這個(gè)實(shí)現(xiàn)Basic認(rèn)證的AuthenticationFilter之前,我們不妨先來(lái)看看使用了這個(gè)自定義AuthenticationFilter會(huì)產(chǎn)生怎樣的效果。我們?cè)谝粋€(gè)ASP.NET MVC應(yīng)用中定義了如下一個(gè)HomeController,定義其中的默認(rèn)Action方法Index會(huì)輸出以三種形式體現(xiàn)的“當(dāng)前用戶(hù)名”。HomeController類(lèi)型上應(yīng)用的AuthenticateAttribute特性正是我們自定義的AuthenticationFilter。

1: 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: }

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

這個(gè)用于實(shí)現(xiàn)Basic認(rèn)證的AuthenticateAttribute定義如下,簡(jiǎn)單起見(jiàn)我們將帳號(hào)采用的用戶(hù)名和密碼保存在一個(gè)靜態(tài)字段中。具體的認(rèn)證實(shí)現(xiàn)在實(shí)現(xiàn)的OnAuthentication方法中,我們?cè)谠摲椒ㄖ姓{(diào)用IsAuthenticated判斷請(qǐng)是否經(jīng)過(guò)認(rèn)證,并在認(rèn)證成功的情況下得到代表請(qǐng)求用戶(hù)的Principal對(duì)象,然對(duì)作為參數(shù)的AuthenticationContext對(duì)象的Principal屬性進(jìn)行賦值。對(duì)于沒(méi)有經(jīng)過(guò)認(rèn)證的請(qǐng)求,我們會(huì)調(diào)用另一個(gè)方法ProcessUnauthenticatedRequest對(duì)其進(jìn)行處理。

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: }

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


作者:蔣金楠
微信公眾賬號(hào):大內(nèi)老A
微博:www.weibo.com/artech
如果你想及時(shí)得到個(gè)人撰寫(xiě)文章以及著作的消息推送,或者想看看個(gè)人推薦的技術(shù)資料,可以?huà)呙枳筮叾S碼(或者長(zhǎng)按識(shí)別二維碼)關(guān)注個(gè)人公眾號(hào)(原來(lái)公眾帳號(hào)蔣金楠的自媒體將會(huì)停用)。
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。 原文鏈接

總結(jié)

以上是生活随笔為你收集整理的[ASP.NET MVC] 利用自定义的AuthenticationFilter实现Basic认证的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。