• .Net Core 2.0 preview1实现自定义认证方案


    Microsoft.Authentication的使用方法在2.0中发生了比较大的变化,在1.1中认证配置是在Configure中完成。

    public void ConfigureServices(IServiceCollection services)
    {
      services.AddAuthentication();
    }
    
    public void Configure(IApplicationBuilder app)
    {
      app.UseJwtBearerAuthentication(new JwtBearerOptions
      {
      Authority = Configuration["jwt:authority"],
      Audience = Configuration["jwt:audience"],
      Events = new JwtBearerEvents()
      {
        OnAuthenticationFailed = c =>
        {
          c.HandleResponse();
          c.Response.StatusCode = 500;
          c.Response.ContentType = "text/plain";
          if (Environment.IsDevelopment())
          {
            return c.Response.WriteAsync(c.Exception.ToString());
          }
          return c.Response.WriteAsync("An error occurred processing your authentication.");
        }  
      }
    });

    UseJwtBearerAuthentication其实是添加了一个中间件

            public static IApplicationBuilder UseJwtBearerAuthentication(this IApplicationBuilder app, JwtBearerOptions options)
            {
                if (app == null)
                {
                    throw new ArgumentNullException(nameof(app));
                }
                if (options == null)
                {
                    throw new ArgumentNullException(nameof(options));
                }
    
                return app.UseMiddleware<JwtBearerMiddleware>(Options.Create(options));
            }

    而在2.0中,认证配置则是在ConfigureServices中完成,并且通过Scheme-Handler的形式来实现多种认证方案的策略式选择。

    public void ConfigureServices(IServiceCollection services)
    {
      services.AddJwtBearerAuthentication(o =>
      {
        o.Authority = Configuration["jwt:authority"];
        o.Audience = Configuration["jwt:audience"];
        o.Events = new JwtBearerEvents()
        {
          OnAuthenticationFailed = c =>
          {
                  c.HandleResponse();
                  c.Response.StatusCode = 500;
                  c.Response.ContentType = "text/plain";
                  if (Environment.IsDevelopment())
                  {
                      return c.Response.WriteAsync(c.Exception.ToString());
                  }
                  return c.Response.WriteAsync("An error occurred processing your authentication.");
              }
           };
        });
    }
    
    public void Configure(IApplicationBuilder app)
    {
        app.UseAuthentication();
    }  
    public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services, string authenticationScheme, Action<JwtBearerOptions> configureOptions)
    {
        return services.AddScheme<JwtBearerOptions, JwtBearerHandler>(authenticationScheme, configureOptions);
    }
    
    public static IApplicationBuilder UseAuthentication(this IApplicationBuilder app)
    {
      if (app == null)
       {
         throw new ArgumentNullException(nameof(app));
       }         
       return app.UseMiddleware<AuthenticationMiddleware>();
    }
    
    namespace Microsoft.AspNetCore.Authentication
    {
        public class AuthenticationMiddleware
        {
            private readonly RequestDelegate _next;
    
            public AuthenticationMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes)
            {
                if (next == null)
                {
                    throw new ArgumentNullException(nameof(next));
                }
                if (schemes == null)
                {
                    throw new ArgumentNullException(nameof(schemes));
                }
    
                _next = next;
                Schemes = schemes;
            }
    
            public IAuthenticationSchemeProvider Schemes { get; set; }
    
            public async Task Invoke(HttpContext context)
            {
                context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
                {
                    OriginalPath = context.Request.Path,
                    OriginalPathBase = context.Request.PathBase
                });
    
                // REVIEW: alternatively could depend on a routing middleware to do this
    
                // 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.1的时候我们使用不同的认证方案时,是使用不同的中间件来实现认证,而2.0则刚好反过来,官方实现了一个统一的认证中间件,在中间件里获取对应的Scheme的Handler,然后调用Handler来完成认证过程。

    在2.0中实现自己的认证方案非常方便——自己实现一个AuthenticationSchemeOptions和一个AuthenticationHandler,然后通过AddScheme注入并指定Scheme就可以了。

    以官方JwtBearerAuthentication为例:

    源码在此:https://github.com/aspnet/Security/tree/rel/2.0.0-preview1/src/Microsoft.AspNetCore.Authentication.JwtBearer

    在ConfigureServices中调用AddJwtBearerAuthentication,其实是调用了AddScheme,authenticationScheme是JwtBearerDefaults.AuthenticationScheme。

    JwtBearerOptions是继承AuthenticationSchemeOptions的类,用来保存认证配置。
    JwtBearerHandler继承了AuthenticationHandler<JwtBearerOptions>,用于认证过程处理,需要什么依赖,直接从构造函数注入。关键在HandleAuthenticateAsync和HandleUnauthorizedAsync这两个方法。
     
    认证流程是这样的:
    1. ConfigureServices中调用AddScheme提供<AuthenticationSchemeOptions,AuthenticationHandler>并指定Scheme。
    2. Configure中调用UseAuthentication。
    3. 访问一个带有AuthorizeAttribute的Action。
    4. AuthenticationMiddleware获取默认Scheme(或者AuthorizeAttribute指定的Scheme)的AuthenticationHandler,调用到Handler的HandleAuthenticateAsync,根据返回结果来决定是调用HandleUnauthorizedAsync还是HandleForbiddenAsync。
     
    我们自己实现认证方案主要就是要实现HandleAuthenticateAsync这个方法,想怎么认证就怎么写。
  • 相关阅读:
    ping和telnet
    nginx下No input file specified错误的解决
    【Git】删除某个全局配置项
    windows7使用Sphinx+PHP+MySQL详细介绍
    TortoiseGit需要重复填写用户名和密码的问题
    【算法】字符串数组的排序时间复杂度问题
    java随机生成6位随机数 5位随机数 4位随机数
    Linux下MySQL报Table 'xxx' doesn't exist错误解决方法,表名存在大小写区分
    Cannot find ./catalina.sh The file is absent or does not have execute permission This file is nee
    Linux 服务器安装jdk,mysql,tomcat简要教程
  • 原文地址:https://www.cnblogs.com/zonciu/p/7141139.html
Copyright © 2020-2023  润新知