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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM