认证Authentication

认证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;
                });
AddJwtBearer("Bearer+IdentityServerAuthenticationJwt") 
增加 builder.AddScheme<JwtBearerOptions, JwtBearerHandler>("BearerIdentityServerAuthenticationJwt")
首先在AuthenticationOptions增加BearerIdentityServerAuthenticationJwt,类型是JwtBearerHandler)注入JwtBearerOptions、JwtBearerHandler单例
增加Bearer,类型是IdentityServerAuthenticationHandler,Authentication handler for validating both JWT and reference tokens
 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

AuthenticationSchemeBuilder:名字(scheme name)、展示名字、Type(IAuthenticationHandler)、用来build方法创建AuthenticationScheme (两者之前的差别)
 
2、AuthenticationSchemeProvider,创建的时候,就从上面Option里面取出schemes,创建保存是IDictionary<string, AuthenticationScheme> _schemes;
_requestHandlers:typeof(IAuthenticationRequestHandler).IsAssignableFrom(scheme.HandlerType) 的集合。
 
 3、authenticationHandlerProvider:是需要根据提供Scheme名字得到IAuthenticationHandler,它要使用IAuthenticationSchemeProvider,取出对应的AuthenticationScheme,再根据创建对应IAuthenticationHandle的实例。再进行初始化(赋值Scheme和HttpContext)。 
IAuthenticationRequestHandler:是用于确定处理程序是否要参与请求处理。如果返回true,说明认证停止。通常有远程认证中使用
   
4、AuthenticationService:使用哪个scheme,没有指定则使用default,使用这个scheme下定义的IAuthenticationHandler,创建IAuthenticationHandler  
AuthenticateResult:它是AuthenticationHandler对象执行Authenticate方法的认证结果
它有AuthenticationTick(核心对象、ClaimsPrincipal,AuthenticationScheme,在授权中验证scheme、AuthenticationProperties)、ClaimsPrincipal(用来给HttpContext.User)、AuthenticationProperties(et(表示证书颁发的相关信息,如颁发时间,过期时间,重定向地址等)),有success 、fail静态方法
 
二、AuthenticationHandler

它定义一个抽象方法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 IAuthenticationHandler
{
Task InitializeAsync(AuthenticationScheme scheme, HttpContext context);
Task<AuthenticateResult> AuthenticateAsync();
Task ChallengeAsync(AuthenticationProperties properties);
Task ForbidAsync(AuthenticationProperties properties);
}
 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);
    }

 

posted on 2019-12-17 04:27  dollymi  阅读(1700)  评论(0编辑  收藏  举报

导航