认证authentication,基于声明式认证
基于HttpContext的认证的扩展,SignIn(成功会颁发一个加密的凭证)、SignOut、Authenticate (验证signin颁发证书,返回authenticationResult,表明用户身份)、Challenge(返回一个需要标识身份提示用户登录,通常返回401)、 Forbid (通用返回403)、 GetTocken,调用AuthenticationService同名方法执行
在aspnetcore的http下authentication.abstrations与authentication.core对关键抽象进行描述,Security下则是Authentication则是具体的实现
服务注入 AddAuthentication(),可以直接指定defaultscheme,可以使用委托方法指定AuthenticationOption下面的defaultscheme,authenticatescheme,signscheme,signoutscheme,defaultchallenge
指定相应的hander。注入最重要AuthenticationService、 AuthenticationHandlerProvider、AuthenticationSchemeProvider三个重要对象
services.AddAuthenticationCore(); services.AddDataProtection(); services.AddWebEncoders(); services.TryAddSingleton<ISystemClock, SystemClock>(); return new AuthenticationBuilder(services); public static AuthenticationBuilder AddAuthentication(this IServiceCollection services, string defaultScheme) => services.AddAuthentication(o => o.DefaultScheme = defaultScheme); public static AuthenticationBuilder AddAuthentication(this IServiceCollection services, Action<AuthenticationOptions> configureOptions) services.Configure(configureOptions);
通过AddAuthentication返回的AuthenticationBuilder,通过AddJwtBearer(或者AddCookie)来指定Scheme类型和需要验证的参数
context.Services.AddAuthentication("Bearer") .AddIdentityServerAuthentication(options => { options.Authority = configuration["AuthServer:Authority"]; options.ApiName = configuration["AuthServer:ApiName"]; options.RequireHttpsMetadata = false; });
public static AuthenticationBuilder AddIdentityServerAuthentication(this AuthenticationBuilder builder, string authenticationScheme, Action<IdentityServerAuthenticationOptions> configureOptions) { builder.AddJwtBearer(authenticationScheme + IdentityServerAuthenticationDefaults.JwtAuthenticationScheme, configureOptions: null); builder.AddOAuth2Introspection(authenticationScheme + IdentityServerAuthenticationDefaults.IntrospectionAuthenticationScheme, configureOptions: null); builder.Services.AddSingleton<IConfigureOptions<JwtBearerOptions>>(services => { var monitor = services.GetRequiredService<IOptionsMonitor<IdentityServerAuthenticationOptions>>(); return new ConfigureInternalOptions(monitor.Get(authenticationScheme), authenticationScheme); }); builder.Services.AddSingleton<IConfigureOptions<OAuth2IntrospectionOptions>>(services => { var monitor = services.GetRequiredService<IOptionsMonitor<IdentityServerAuthenticationOptions>>(); return new ConfigureInternalOptions(monitor.Get(authenticationScheme), authenticationScheme); }); return builder.AddScheme<IdentityServerAuthenticationOptions, IdentityServerAuthenticationHandler>(authenticationScheme, configureOptions); }
在Startup类中的Configure方法通过添加UseAuthentication注册认证中间件(AuthenticationMiddleware),在认证过程中,通过AuthenticationSchemeProvider获取正确的Scheme,在AuthenticationService中通过Scheme和AuthenticationHandlerProvider获取正确的AuthenticationHandler,最后通过对应的AuthenticationHandler的AuthenticateAsync方法进行认证流程。
GetRequestHandlerSchemesAsync(多个AuthenticationScheme)=》GetDefaultAuthenticateSchemeAsync(一个AuthenticationScheme、执行handle下的AuthenticateAsync方法,返回AuthenticateResult给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); }
1、AuthenticationOption
scheme:有cookie, bearer, oauth, openid等等,保存着IList<AuthenticationSchemeBuilder> schemes,SchemeMap
DefaultScheme、DefaultAuthenticateScheme、DefaultSignInScheme、DefaultSignOutScheme、DefaultChallengeScheme、DefaultForbidScheme??
什么时候赋值??schememap对应是哪个AuthenticationSchemeBuilder,即使用哪个IAuthenticationHandle(方法有InitializeAsync、AuthenticateAsync、ChallengeAsync、ForbidAsync,Signin SignOut方法单独出来)处理它的通用方法是AddScheme(),即增加到IList<AuthenticationSchemeBuilder>,每一个schemeName映射 Dictionary< schemeName , AuthenticationSchemeBuilder> schememap
它定义一个抽象方法HandleAuthenticateAsync
,并使用HandleAuthenticateOnceAsync
方法来保证其在每次认证只执行一次。而HandleAuthenticateAsync
是认证的核心,交给具体的认证Handler负责实现。而对于 ChallengeAsync, ForbidAsync 等方法也提供了默认的实现。
而对于HandleAuthenticateAsync
的实现,大致的逻辑就是从请求中获取上面发放的身份令牌,然后解析成AuthenticationTicket
,并经过一系列的验证,最终返回ClaimsPrincipal对象。
jwtScheme=Bearer+IdentityServerAuthenticationJwt =》使用是JwtBearerHandler
introspectionScheme=Bearer+IdentityServerAuthenticationIntrospection 》对reference token处理
在HttpContext.Item存储idsrv4:tokenvalidation:token
RemoteAuthenticationHandler
便是所有远程认证的抽象基类了,它继承自AuthenticationHandler
,并实现了IAuthenticationRequestHandler
接口:
而RemoteAuthenticationHandler
中核心的认证逻辑便是 HandleRequestAsync
方法,它主要包含2个步骤:
首先执行一个抽象方法HandleRemoteAuthenticateAsync
,由具体的Handler来实现,该方法返回的HandleRequestResult
对象包含验证的结果(跳过,失败,成功等),在成功时会包含一个ticket对象若上一步验证成功,则根据返回的ticket,获取到ClaimsPrincipal
对象,并调用其它认证Handler的Context.SignInAsync
方法。
远程Hander会在用户未登录时,指引用户跳转到认证服务器,登录成功后,解析认证服务器传回的凭证,最终依赖于本地Handler来保存身份令牌。当用户再次访问则无需经过远程Handler,直接交给本地Handler来处理。
public interface IAuthenticationRequestHandler : IAuthenticationHandler
{
/// <summary>
/// Returns true if request processing should stop.
/// </summary>
/// <returns><see langword="true" /> if request processing should stop.</returns>
Task<bool> HandleRequestAsync();
}
public interface IAuthenticationSignInHandler : IAuthenticationSignOutHandler
{
Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties);
}
public interface IAuthenticationSignOutHandler : IAuthenticationHandler
{
Task SignOutAsync(AuthenticationProperties properties);
}