title: "AspNetCore3.1_Secutiry源碼解析_2_Authentication_核心流程"
date: 2020-03-18T21:19:15+08:00
draft: false
---架構
框架提供了三個依賴注入重載方法。框架
//注入認證服務 services.AddAuthentication(); //注入認證服務並制定默認架構名 services.AddAuthentication("Cookies"); //注入認證服務並設置配置項 services.AddAuthentication(config => { });
看看注入代碼async
public static AuthenticationBuilder AddAuthentication(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException(nameof(services)); } services.AddAuthenticationCore(); services.AddDataProtection(); services.AddWebEncoders(); services.TryAddSingleton<ISystemClock, SystemClock>(); return new AuthenticationBuilder(services); }
AddAuthenticationCore注入了認證服務的核心對象。這個方法在Authentication.Core項目,這個項目定義了認證服務的核心對象,在Authentication.Abstractions項目中定義了核心接口。ide
AddAuthenticationCore方法注入了IAuthenticationService,IClaimsTransformation,IAuthenticationHandlerProvider,IAuthenticationSchemeProvideroop
public static IServiceCollection AddAuthenticationCore(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException(nameof(services)); } services.TryAddScoped<IAuthenticationService, AuthenticationService>(); services.TryAddSingleton<IClaimsTransformation, NoopClaimsTransformation>(); // Can be replaced with scoped ones that use DbContext services.TryAddScoped<IAuthenticationHandlerProvider, AuthenticationHandlerProvider>(); services.TryAddSingleton<IAuthenticationSchemeProvider, AuthenticationSchemeProvider>(); return services; }
認證服務,定義了五個方法ui
經過AuthenticateAsync方法源代碼能夠看到,AuthenticateService只是作了控制器的角色,校驗schema,根據schema獲取handler,主要的認證邏輯是由handler處理。其餘的方法基本也是這樣的邏輯。this
public virtual async Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme) { if (scheme == null) { var defaultScheme = await Schemes.GetDefaultAuthenticateSchemeAsync(); scheme = defaultScheme?.Name; if (scheme == null) { throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultAuthenticateScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions)."); } } var handler = await Handlers.GetHandlerAsync(context, scheme); if (handler == null) { throw await CreateMissingHandlerException(scheme); } var result = await handler.AuthenticateAsync(); if (result != null && result.Succeeded) { var transformed = await Transform.TransformAsync(result.Principal); return AuthenticateResult.Success(new AuthenticationTicket(transformed, result.Properties, result.Ticket.AuthenticationScheme)); } return result; }
該接口只有一個方法,用於轉換Claims。默認注入的NoopClaimsTransformation,不會作任何操做。若是須要對Claims作一些處理,實現IClaimsTransformation並覆蓋注入就能夠了。code
public class NoopClaimsTransformation : IClaimsTransformation { /// <summary> /// Returns the principal unchanged. /// </summary> /// <param name="principal">The user.</param> /// <returns>The principal unchanged.</returns> public virtual Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { return Task.FromResult(principal); } }
上面提到過handler處理了主要的認證業務邏輯,這個接口能夠根據schema獲取handler。
orm
該接口主要定義了一些schema的操做方法。中間件
AuthenticationScheme主要有三個屬性,經過HandlerType與handler創建了關聯。
除了核心對象,還注入了用於數據保護和解碼的輔助對象
services.AddDataProtection(); services.AddWebEncoders();
中間件會優先在容器中找IAuthenticationRequestHandler的實現,若是handler不爲空的話,則執行handler的HandleRequestAsync方法。IAuthenticationRequestHandler一般在遠程認證(如:OAuth, OIDC等)中使用。
若是沒有IAuthenticationRequestHandler的實現,則會找默認schema,執行默認schema對應handler的AuthenticationAsync方法,認證成功後,給HttpContext的User對象賦值。
public async Task Invoke(HttpContext context) { context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature { OriginalPath = context.Request.Path, OriginalPathBase = context.Request.PathBase }); // Give any IAuthenticationRequestHandler schemes a chance to handle the request var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>(); foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync()) { var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler; if (handler != null && await handler.HandleRequestAsync()) { return; } } var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); if (defaultAuthenticate != null) { var result = await context.AuthenticateAsync(defaultAuthenticate.Name); if (result?.Principal != null) { context.User = result.Principal; } } await _next(context); }