.NetCore源码阅读笔记系列之Security (二) 自定义认证实践

通过前面对AddCookie 或者 AddOpenIdConnect 等了解,其实里面都实现了一个AuthenticationHandler<TOptions>的认证处理,接下来我们来简单自定义一个试试

首先我来实现下面这个方式,我添加了一个AddLIYOUMING()

 services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = "LIYOUMINGScheme";
                options.DefaultChallengeScheme = "LIYOUMINGScheme";
            })
            .AddLIYOUMING(o=> {


            });

扩展下AuthenticationBuilder就行了,看下扩展

  /// <summary>
    /// 黎又铭自定义可扩展
    /// </summary>
    public static class LIYOUMINGExtensions
    {
        public static AuthenticationBuilder AddLIYOUMING(this AuthenticationBuilder builder)
        {

            builder.AddLIYOUMING("LIYOUMINGScheme", o => { });
            return builder;
        }

        public static AuthenticationBuilder AddLIYOUMING(this AuthenticationBuilder builder, Action<LIYOUMINGOptions> configureOptions)
        {
            builder.AddLIYOUMING("LIYOUMINGScheme", configureOptions);
            return builder;
        }

        public static AuthenticationBuilder AddLIYOUMING(this AuthenticationBuilder builder, string defaultScheme, Action<LIYOUMINGOptions> configureOptions)
        {
            builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<LIYOUMINGOptions>, LIYOUMINGPostConfigureOptions>());
            builder.AddScheme<LIYOUMINGOptions, LIYOUMINGHandler>(defaultScheme, "", configureOptions);
            return builder;
        }
    }

我定义了LIYOUMINGOptions参数类,但是我并没有添加任何参数明白原理即可,需要继承AuthenticationSchemeOptions,可以重写验证处理,为什么要继承AuthenticationSchemeOptions,是因为AuthenticationHandler<TOptions>泛型限定

public abstract class AuthenticationHandler<TOptions> : IAuthenticationHandler where TOptions : AuthenticationSchemeOptions, new()
public class LIYOUMINGOptions : AuthenticationSchemeOptions
    {
        public override void Validate()
        {
            base.Validate();
        }
        public override void Validate(string scheme)
        {
            base.Validate(scheme);
        }
    }

还需要处理下配置,需要去实现IPostConfigureOptions

 builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<LIYOUMINGOptions>, LIYOUMINGPostConfigureOptions>());
public class LIYOUMINGPostConfigureOptions :IPostConfigureOptions<LIYOUMINGOptions>
    {
        public void PostConfigure(string name, LIYOUMINGOptions options)
        {
          
        }
    }

现在我们需要一个Handler来继承AuthenticationHandler<TOptions>,这里我定义了一个LIYOUMINGHandler,里面去重写相关认证方法即可,这里关键是AddScheme中的具体处理如下,配置绑定配置,注册Handler服务:

 public virtual AuthenticationBuilder AddScheme<TOptions, THandler>(string authenticationScheme, string displayName, Action<TOptions> configureOptions)
            where TOptions : AuthenticationSchemeOptions, new()
            where THandler : AuthenticationHandler<TOptions>
        {
            Services.Configure<AuthenticationOptions>(o =>
            {
                o.AddScheme(authenticationScheme, scheme => {
                    scheme.HandlerType = typeof(THandler);
                    scheme.DisplayName = displayName;
                });
            });
            if (configureOptions != null)
            {
                Services.Configure(authenticationScheme, configureOptions);
            }
            Services.AddTransient<THandler>();
            return this;
        }

下面就来看下我自定义的Handler中的处理

  public class LIYOUMINGHandler : AuthenticationHandler<LIYOUMINGOptions>
    {
        public LIYOUMINGHandler(IOptionsMonitor<LIYOUMINGOptions> options, ILoggerFactory logger, UrlEncoder encoder,IDataProtectionProvider dataProtection, ISystemClock clock)
             : base(options, logger, encoder, clock)
        {


        }

        /// <summary>
        /// 这里就是具体的认证处理了
        /// </summary>
        /// <returns></returns>
        protected async override  Task<AuthenticateResult> HandleAuthenticateAsync()
        {

            AuthenticationTicket ticket = new AuthenticationTicket(new System.Security.Claims.ClaimsPrincipal { }, "LIYOUMINGScheme");
            AuthenticateResult result = AuthenticateResult.Success(ticket);
         
            return await Task.FromResult(result);
        }
        protected override Task HandleChallengeAsync(AuthenticationProperties properties)
        {

           return base.HandleChallengeAsync(properties);
        }

        protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
        {
            return base.HandleForbiddenAsync(properties);
        }

        protected override Task InitializeEventsAsync()
        {
            return base.InitializeEventsAsync();
        }
    }

有些东西就没写了,无论你是cookie认证,还是OpenId 或者其他的都是在这里来处理的,只是具体的处理细节不一样,前面一篇文章说过HandleAuthenticateAsync 其实是抽象方法在父类中AuthenticateAsync()被调用,而AuthenticateAsync(),在IAuthenticationHandleProvider被调用,所以这里具体看业务了

  AuthenticationTicket ticket = new AuthenticationTicket(new System.Security.Claims.ClaimsPrincipal { }, "LIYOUMINGScheme");
            AuthenticateResult result = AuthenticateResult.Success(ticket);
         
            return await Task.FromResult(result);

这里我举个例子,返回的是AuthenticateResult包裹的AuthenticationTicket,AuthenticationTicket中包含了身份信息,当然还有HandleChallengeAsync、HandleForbiddenAsync、InitializeEventsAsync等就不做介绍了

其实算下加上扩展就4个类LIYOUMINGExtensions、LIYOUMINGHandler、LIYOUMINGOptions、LIYOUMINGPostConfigureOptions就基本上描述了

下面来体验下:

在Configure中添加调试运行断点进入了Handler中的HandleAuthenticateAsync,就实现了HandleAuthenticateAsync认证在手,天下你有,任你发挥你的能力

  app.UseAuthentication();
            app.Use(async (context, next) =>
            {
                var user = context.User; 
                if (user?.Identity?.IsAuthenticated ?? false)
                {
                    await next();
                }
                else
                {
                    await context.ChallengeAsync();
                }
                await context.Response.WriteAsync("Hello World!");
            });

猜你喜欢

转载自www.cnblogs.com/liyouming/p/9922701.html
今日推荐