小編給大家分享一下ASP.NET Core Authentication如何認(rèn)證實(shí)現(xiàn)方法,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
創(chuàng)新互聯(lián)提供成都網(wǎng)站制作、網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì),成都品牌網(wǎng)站建設(shè),廣告投放等致力于企業(yè)網(wǎng)站建設(shè)與公司網(wǎng)站制作,十年的網(wǎng)站開發(fā)和建站經(jīng)驗(yàn),助力企業(yè)信息化建設(shè),成功案例突破數(shù)千家,是您實(shí)現(xiàn)網(wǎng)站建設(shè)的好選擇.追本溯源,從使用開始
首先看一下我們通常是如何使用微軟自帶的認(rèn)證,一般在Startup里面配置我們所需的依賴認(rèn)證服務(wù),這里通過JWT的認(rèn)證方式講解
public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(authOpt => { authOpt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; authOpt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(o => { o.TokenValidationParameters = new TokenValidationParameters { //配置自己所要驗(yàn)證的參數(shù) }; }); }
我們來看一下源碼AddAuthentication主要做了什么
public static class AuthenticationServiceCollectionExtensions { public static AuthenticationBuilder AddAuthentication( this IServiceCollection services, ActionconfigureOptions) { if (services == null) throw new ArgumentNullException(nameof (services)); if (configureOptions == null) throw new ArgumentNullException(nameof (configureOptions)); AuthenticationBuilder authenticationBuilder = services.AddAuthentication(); services.Configure (configureOptions); return authenticationBuilder; } public static AuthenticationBuilder AddAuthentication( this IServiceCollection services) { if (services == null) throw new ArgumentNullException(nameof (services)); services.AddAuthenticationCore(); services.AddDataProtection(); services.AddWebEncoders(); services.TryAddSingleton (); return new AuthenticationBuilder(services); } public static AuthenticationBuilder AddAuthentication( this IServiceCollection services, string defaultScheme) { return services.AddAuthentication((Action ) (o => o.DefaultScheme = defaultScheme)); } ..... }
ConfigureServices方法基本都是服務(wù)的注冊,基于微軟的風(fēng)格,這里的AddAuthenticationCore肯定是我們的認(rèn)證服務(wù)注冊方法,來看一下
public static class AuthenticationCoreServiceCollectionExtensions { ////// Add core authentication services needed for public static IServiceCollection AddAuthenticationCore( this IServiceCollection services) { if (services == null) throw new ArgumentNullException(nameof (services)); services.TryAddScoped. /// (); services.TryAddSingleton (); services.TryAddScoped (); services.TryAddSingleton (); return services; } /// /// Add core authentication services needed for public static IServiceCollection AddAuthenticationCore( this IServiceCollection services, Action. /// configureOptions) { if (services == null) throw new ArgumentNullException(nameof (services)); if (configureOptions == null) throw new ArgumentNullException(nameof (configureOptions)); services.AddAuthenticationCore(); services.Configure (configureOptions); return services; } }
我們看到這里主要注冊了AuthenticationService, AuthenticationHandlerProvider, AuthenticationSchemeProvider這三個(gè)對(duì)象,如文章開頭所說,追本溯源,從使用開始,我們先看一下這三個(gè)對(duì)象是如何在認(rèn)證體系中使用的,且是如何發(fā)揮作用的。
從使用開始
看一下我們的認(rèn)證管道構(gòu)建
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { ... app.UseAuthentication(); ... } public static class AuthAppBuilderExtensions { public static IApplicationBuilder UseAuthentication( this IApplicationBuilder app) { if (app == null) throw new ArgumentNullException(nameof (app)); return app.UseMiddleware(); } }
這里使用了約定的注冊方式UseMiddleware,并且指定使用中間件AuthenticationMiddleware
public class AuthenticationMiddleware { private readonly RequestDelegate _next; public AuthenticationMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes) { if (next == null) throw new ArgumentNullException(nameof (next)); if (schemes == null) throw new ArgumentNullException(nameof (schemes)); this._next = next; this.Schemes = schemes; } public IAuthenticationSchemeProvider Schemes { get; set; } public async Task Invoke(HttpContext context) { context.Features.Set((IAuthenticationFeature) new AuthenticationFeature() { OriginalPath = context.Request.Path, OriginalPathBase = context.Request.PathBase }); IAuthenticationHandlerProvider handlers = context.RequestServices.GetRequiredService (); foreach (AuthenticationScheme authenticationScheme in await this.Schemes.GetRequestHandlerSchemesAsync()) { IAuthenticationRequestHandler handlerAsync = await handlers.GetHandlerAsync(context, authenticationScheme.Name) as IAuthenticationRequestHandler; bool flag = handlerAsync != null; if (flag) flag = await handlerAsync.HandleRequestAsync(); if (flag) return; } AuthenticationScheme authenticateSchemeAsync = await this.Schemes.GetDefaultAuthenticateSchemeAsync(); if (authenticateSchemeAsync != null) { AuthenticateResult authenticateResult = await context.AuthenticateAsync(authenticateSchemeAsync.Name); //實(shí)際的認(rèn)證業(yè)務(wù) if (authenticateResult?.Principal != null) context.User = authenticateResult.Principal; } await this._next(context); } }
在繼續(xù)往下之前,我們先看一下這個(gè)認(rèn)證中間件的作用結(jié)果,當(dāng)認(rèn)證通過時(shí),在HttpContext的User屬性(ClaimPrincipal)賦予身份標(biāo)識(shí),所以在后續(xù)的請(qǐng)求管道中都是基于認(rèn)證結(jié)果中的身份標(biāo)識(shí)做鑒權(quán),這個(gè)我們會(huì)在后面的實(shí)際操作中會(huì)提到。
言歸正傳,在這里引出了我們的兩個(gè)對(duì)象AuthenticationHandlerProvider,AuthenticationSchemeProvider。
重要對(duì)象講解
IAuthenticationSchemeProvider
從名字來看,IAuthenticationSchemeProvider的作用應(yīng)該是提供Scheme的,這也是Provider在微軟的風(fēng)格里面起的作用(類似于工廠模式)。
這個(gè)Scheme是什么呢?很明顯,在Framework時(shí)代,也是有基于不同Scheme驗(yàn)證的,比如Bearer,Cookie,在Aspnet Core中定義不同的Scheme代表著不同的認(rèn)證處理方式,具體體現(xiàn)是在每個(gè)Scheme中包含對(duì)應(yīng)的IAuthenticationHandler類型的Handler,由它來完成跟自身Scheme相關(guān)的認(rèn)證處理。如果沒有定義會(huì)怎么樣?仔細(xì)看上面這塊源碼,只有當(dāng)AuthenticationScheme不為空時(shí)才會(huì)做認(rèn)證,否則一旦在Controller打上鑒權(quán)標(biāo)簽[Authorize],將會(huì)直接返回401,所以我們必須指定自己的Scheme。
那么我們在哪里指定我們的Scheme類似呢?我們先返回到ConfigureService的AddJwtBearer,使用過的朋友們肯定知道,這里獲取的Scheme是我們在ConfigureService通過Addxxx scheme指定的Scheme類型。這里我們是使用JWT的
在這里指定了TOptions 為JwtBearerOptions,而THandler為JwtBearerHandler。
public virtual AuthenticationBuilder AddScheme( string authenticationScheme, string displayName, Action configureOptions) where TOptions : AuthenticationSchemeOptions, new() where THandler : AuthenticationHandler { return this.AddSchemeHelper (authenticationScheme, displayName, configureOptions); } private AuthenticationBuilder AddSchemeHelper ( string authenticationScheme, string displayName, Action configureOptions) where TOptions : class, new() where THandler : class, IAuthenticationHandler { this.Services.Configure ((Action ) (o => o.AddScheme(authenticationScheme, (Action ) (scheme => { scheme.HandlerType = typeof (THandler); scheme.DisplayName = displayName; })))); if (configureOptions != null) this.Services.Configure (authenticationScheme, configureOptions); this.Services.AddTransient (); return this; }
注意這里TOptions 是需要繼承AuthenticationSchemeOptions的,在這里是JwtBearerOptions,而THandler是AuthenticationHandler
我們回到Scheme的分析繼續(xù)往下,首先看一下AuthenticationScheme的定義
public class AuthenticationScheme { ///Constructor. public AuthenticationScheme(string name, string displayName, Type handlerType) { if (name == null) throw new ArgumentNullException(nameof (name)); if (handlerType == (Type) null) throw new ArgumentNullException(nameof (handlerType)); if (!typeof (IAuthenticationHandler).IsAssignableFrom(handlerType)) throw new ArgumentException("handlerType must implement IAuthenticationHandler."); this.Name = name; this.HandlerType = handlerType; this.DisplayName = displayName; } ///The name of the authentication scheme. public string Name { get; } ////// The display name for the scheme. Null is valid and used for non user facing schemes. /// public string DisplayName { get; } ////// The public Type HandlerType { get; } }type that handles this scheme. ///
在這里可以看到,如果要使用Aspnet Core自身的認(rèn)證體系,需先注冊Scheme,并且該Scheme必須指定一個(gè)類型為IAuthenticationHandler的Handler,否則會(huì)拋出異常。(這個(gè)其實(shí)在AddxxxScheme的時(shí)候已經(jīng)指定了AuthenticationHandler)
我們再看一下IAuthenticationSchemeProvider的GetRequestHandlerSchemesAsync方法做了什么
public virtual Task> GetRequestHandlerSchemesAsync() { return Task.FromResult >((IEnumerable ) this._requestHandlers); }
這東西返回了_requestHandlers,這是什么?看代碼
public class AuthenticationSchemeProvider : IAuthenticationSchemeProvider { private readonly object _lock = new object(); private readonly AuthenticationOptions _options; private readonly IDictionary_schemes; private readonly List _requestHandlers; /// /// Creates an instance of public AuthenticationSchemeProvider(IOptions/// using the specified , /// options) : this(options, (IDictionary ) new Dictionary ((IEqualityComparer ) StringComparer.Ordinal)) { } /// /// Creates an instance of protected AuthenticationSchemeProvider( IOptions/// using the specified and . /// options, IDictionary schemes) { this._options = options.Value; IDictionary dictionary = schemes; if (dictionary == null) throw new ArgumentNullException(nameof (schemes)); this._schemes = dictionary; this._requestHandlers = new List (); foreach (AuthenticationSchemeBuilder scheme in this._options.Schemes) this.AddScheme(scheme.Build()); } public virtual void AddScheme(AuthenticationScheme scheme) { if (this._schemes.ContainsKey(scheme.Name)) throw new InvalidOperationException("Scheme already exists: " + scheme.Name); lock (this._lock) { if (this._schemes.ContainsKey(scheme.Name)) throw new InvalidOperationException("Scheme already exists: " + scheme.Name); if (typeof (IAuthenticationRequestHandler).IsAssignableFrom(scheme.HandlerType)) this._requestHandlers.Add(scheme); this._schemes[scheme.Name] = scheme; } } ..... }
這東西就是把我們在認(rèn)證注冊服務(wù)中指定的scheme,通過解析出的AuthenticationSchemeProvider 的構(gòu)造函數(shù)加載來的,進(jìn)而返回一系列的List IAuthenticationHandlerProvider 我們看到,AuthenticationMiddleware中用到了IAuthenticationHandlerProvider的GetHandlerAsync方法,那我們先看一下這個(gè)方法的作用 在創(chuàng)建Handler的時(shí)候,是先從AuthenticationScheme中獲取,如果不存在則通過ActivatorUtilities創(chuàng)建。 獲取到Handle后,將會(huì)放在_handlerMap字典里面,當(dāng)下次獲取Handler的時(shí)候,將直接從緩存中獲取。 IAuthenticationService 這個(gè)對(duì)象是在AuthenticationMiddleware中最后才用到的,而且是基于HttpContext的擴(kuò)展被調(diào)用 這里主要調(diào)用了IAuthenticationService的AuthenticateAsync方法,看一下這個(gè)方法做了什么 這里其實(shí)就是我們在前面講的根據(jù)Scheme獲取對(duì)應(yīng)的AuthenticationHandler,然后調(diào)用AuthenticateAsync()方法,這個(gè)方法調(diào)用了核心方法HandleAuthenticateOnceAsync,然后再調(diào)用HandleAuthenticateAsync()這個(gè)核心的認(rèn)證方法。 從上圖看到這個(gè)HandleAuthenticateAsync是個(gè)抽象方法,我們的子類都需要實(shí)現(xiàn)這個(gè)方法的動(dòng)作,基于本文的例子,我們看一下JwtBearerHandler的一個(gè)實(shí)際認(rèn)證。 這個(gè)方法有點(diǎn)長,主要是從Request.Headers里面獲取Authorization的Bearer出來解析,再在AddJwtBearer中傳入的委托參數(shù)JwtBearerOptions的TokenValidationParameters屬性作為依據(jù)進(jìn)行對(duì)比來進(jìn)行認(rèn)證是否通過與否。 總結(jié) 本文對(duì) ASP.NET Core 的認(rèn)證流程做了一個(gè)源碼分析流程介紹,由于是源碼分析篇,所以可能會(huì)比較枯燥和苦澀難懂。在后面的真正使用過程中,然后再結(jié)合本篇的一個(gè)總結(jié)流程,相信大家會(huì)逐漸開朗。 在Startup類中的ConfigureServices方法通過添加AddAuthentication注冊我們最主要的三個(gè)對(duì)象AuthenticationService, AuthenticationHandlerProvider, AuthenticationSchemeProvider 通過AddAuthentication返回的AuthenticationBuilder 通過AddJwtBearer(或者AddCookie)來指定Scheme類型和需要驗(yàn)證的參數(shù) 在Startup類中的Configure方法通過添加UseAuthentication注冊認(rèn)證中間件 在認(rèn)證過程中,通過AuthenticationSchemeProvider獲取正確的Scheme,在AuthenticationService中通過Scheme和AuthenticationHandlerProvider獲取正確的AuthenticationHandler,最后通過對(duì)應(yīng)的AuthenticationHandler的AuthenticateAsync方法進(jìn)行認(rèn)證流程 以上是“ASP.NET Core Authentication如何認(rèn)證實(shí)現(xiàn)方法”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!public class AuthenticationHandlerProvider : IAuthenticationHandlerProvider
{
private Dictionary
public static class AuthenticationHttpContextExtensions
{
public static Task
public class AuthenticationService : IAuthenticationService
{
public IAuthenticationSchemeProvider Schemes { get; }
public IAuthenticationHandlerProvider Handlers { get; }
public IClaimsTransformation Transform { get; }
public virtual async Task
public class JwtBearerHandler : AuthenticationHandler
文章題目:ASP.NETCoreAuthentication如何認(rèn)證實(shí)現(xiàn)方法-創(chuàng)新互聯(lián)
轉(zhuǎn)載源于:http://weahome.cn/article/idoso.html