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); }