.NetCore源碼閱讀筆記系列之Security (一) Authentication & AddCookie


 

如果你使用過.NetCore開發過程序,你會很清楚,在其中我們經常會用到一些如下的代碼

 services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            }).AddCookie("Cookies",options=>{
      
  
        });

然后添加了中間件

   app.UseAuthentication();

然而這些中間內部、服務之間怎么去處授權的呢?接下來就來探討一下。

先來說說UseAuthentication這個都做了什么事情

首先我們先來看下在判斷授權的時候是用HttpContext.User中獲取了身份信息,從身份中獲取了IsAuthenticated來判斷是否認證,通過這些我們發現其實 UseAuthentication就做了下面的事情,通過app.UseMiddleware<AuthenticationMiddleware>();中間件將身份信息寫入到上下文對象中的User中

 context.User = result.Principal;

不然發現在這個過程中,會有一些相關的基礎服務和配置參數,讓后自然而然會想到添加注入服務,然后下面的代碼就出來了,添加認證服務、以及一些初始參數的配置

services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            });

接下來我們來看一看AddAuthentication干了什么事情,寫過擴展的朋友都知道,AddAuthentication只是一個掛載到IServiceCollection上的一個擴展方法,有參數就想到了配置所里擴展方法里面就完成了2件事情

 var builder = services.AddAuthentication();
            services.Configure(configureOptions);

添加授權服務和添加配置服務

這里的builder其實是AuthenticationBuilder,其實這個類也沒做什么事情,就接管了下IServiceCollection服務,以便於在AuthenticationBuilder中完成對services服務調用完成其他的功能,如AddScheme

  public AuthenticationBuilder(IServiceCollection services)
            => Services = services;

管道中中間件像企業的生產流水線一樣,經過一層一層的加工(HttpContext=>HttpRequest、HttpRespose、IFeatureCollection、ClaimsPrincipal)等,最后返回加工好的產品,這里的認證中間件也不例外,主要就是為了附加ClaimsPrincipal而生的

這個圖也不知被用了多少次了,我也用下

接下來就來看下在中間件AuthenticationMiddleware中都做了什么事情

 public static IApplicationBuilder UseAuthentication(this IApplicationBuilder app)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }
            
            return app.UseMiddleware<AuthenticationMiddleware>();
        }

說道中間件不得不提到一個重要的東東RequestDelegate這個對象,他就想一個包裹的產品,穿梭連接在每個中間件游走,就想生產流水線上的傳送產品的傳送帶一樣,傳送做請求中的各種對象

首先要獲取的就是 提供的認證處理服務 IAuthenticationHandlerProvider

 var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();

這里還要說下的就是IAuthenticationSchemeProvider,由於授權參數指定的Scheme指定了獲取授權來源,中間件需要獲取當前配置的Scheme對應的IAuthenticationHandlerProvider處理服務

如果獲取到就處理認證請求,這里要說明下代碼,在.NetCore其他地方對下面處理請求做了接口實現,其實就是AddCookies中的CookieAuthenticationHandler,當找到對應請求就不會在處理了。

 public interface IAuthenticationRequestHandler : IAuthenticationHandler
    {
 
        Task<bool> HandleRequestAsync();
    }

可以看到這樣的實現,需要什么實現就添加什么handle,只是這里AddCookie幫我們處理了

public class CookieAuthenticationHandler :
        AuthenticationHandler<CookieAuthenticationOptions>,
        IAuthenticationSignInHandler,
        IAuthenticationSignOutHandler
    {


    }

 

如果沒有從授權Scheme中找到,說明未認證,需要添加認證身份信息的Scheme,獲取到IAuthenticationService服務

 context.RequestServices.GetRequiredService<IAuthenticationService>().AuthenticateAsync(context, scheme);

這里實際上還是從IAuthenticationHandlerProvider服務提供,只是在IAuthenticationService服務中注入了相關服務,最終還是通過IAuthenticationHandler去實現的

public AuthenticationService(IAuthenticationSchemeProvider schemes, IAuthenticationHandlerProvider handlers, IClaimsTransformation transform)
        {
          /*

        */
        }

那么登錄的時候SignIn做了什么呢?

context.RequestServices.GetRequiredService<IAuthenticationService>().SignInAsync(context, scheme, principal, properties);

從認證服務中調用了SignIn,其實最終都是通過IAuthenticationHandler接口來處理的,SignIn、SignOut都是通過AddCookies中CookieAuthenticationHandler通過實現了IAuthenticationSignInHandler來處理,退出IAuthenticationSignOutHandler,認證則是實現IAuthenticationHandler接口,下面我們針對上面的來畫圖分析下可能要明白一些

 

 

下面在來看下AddCookie都做了什么

 public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<CookieAuthenticationOptions> configureOptions)
        {
            builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureCookieAuthenticationOptions>());
            return builder.AddScheme<CookieAuthenticationOptions, CookieAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
        }

這里添加好了Scheme信息,而在AddScheme中注冊了CookieAuthenticationHandler服務,在這里服務中我們可以看到一個返回認證信息的一個重寫方法,而最終處理認證的就是這個處理,它繼承了AuthenticationHandler<Options>,而在AuthenticationHandler里面去實現了IAuthenticationHandler (Task<AuthenticateResult> AuthenticateAsync()),這個之前說的認證具體實現,下面這個是在 AuthenticationHandler<Options> [protected abstract Task<AuthenticateResult> HandleAuthenticateAsync()] 抽象重寫,實際這個就是在IAuthenticationHandler (Task<AuthenticateResult> AuthenticateAsync())中來實現的

protected abstract Task<AuthenticateResult> HandleAuthenticateAsync();
  public async Task<AuthenticateResult> AuthenticateAsync()
        {
         
            var result = await HandleAuthenticateOnceAsync();
            /*.....*/return result;
        }
 protected Task<AuthenticateResult> HandleAuthenticateOnceAsync()
        {
            if (_authenticateTask == null)
            {
                _authenticateTask = HandleAuthenticateAsync();
            }

            return _authenticateTask;
        }
HandleAuthenticateAsync 被CookieAuthenticationHandler 重寫,后通過一些列處理返回了認證結果信息
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
         /*
            Handle略
        */
            return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name));
        }

 如此類推,總結如下:

AddCookies只是為IAuthenticationHandlerProvider中提供認證服務的來源做工作,所有會有 AddOpenIdConnect、AddJwtBearer、AddWsFederation 以及第三方擴展的 Facebook 、Google、OAuth等等


免責聲明!

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



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