zoukankan      html  css  js  c++  java
  • .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等等

  • 相关阅读:
    hibernate关联关系(多对多)
    hibernate关联关系(一对多)
    hibernate主键生成策略
    hibernate01
    利用Struts2拦截器完成文件上传功能
    layui的CRUD案列
    Struts2的CRUD
    Git中.gitignore文件不起作用
    在 Visual Studio 中使用 Q# 进行量子编程
    Elasticsearch 搜索
  • 原文地址:https://www.cnblogs.com/liyouming/p/9916777.html
Copyright © 2011-2022 走看看