zoukankan      html  css  js  c++  java
  • .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!");
                });

     加深下,在LIYOUMINGHandler我在继承接口IAuthenticationSignInHandler实现SignInAsync、SignOutAsync, 当然这里IAuthenticationSignInHandler继承了IAuthenticationSignOutHandler、IAuthenticationHandler,所以这里可通过SignIn写入信息了,下来来改造下代码,能通过LIYOUMINGHandler进行签入、签出,细节就略了

    public class LIYOUMINGHandler : AuthenticationHandler<LIYOUMINGOptions>,IAuthenticationSignInHandler
    {
     public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
            {
                return Task.CompletedTask;
            }
    
            public Task SignOutAsync(AuthenticationProperties properties)
            {
                return Task.CompletedTask;
            }
    
    }
     app.Use(async (context, next) =>
                {
                    var user = context.User; 
                    if (user?.Identity?.IsAuthenticated ?? false)
                    {
                       await next();
                    }
                    else
                    {
                        ClaimsIdentity claimsIdentity = new ClaimsIdentity();
                        claimsIdentity.AddClaim(new Claim("Test", "LIYOUMING"));
                        ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
                        //签入
                        await context.SignInAsync("LIYOUMINGScheme", claimsPrincipal);
                       
                        await context.Response.WriteAsync("SignInAsync");
                    }
                
                });

    AddAuthentication中间件会先调用HandleAuthenticateAsync处理认证情况,其次上面代码执行后,输出了 SignInAsync,再次刷新的时候再次进入中间件的HandleAuthenticateAsync,这个时候处理认证信息 ,最后也没没有输出

  • 相关阅读:
    angularjs的$on、$emit、$broadcast
    angularjs中的路由介绍详解 ui-route(转)
    ionic入门教程-ionic路由详解(state、route、resolve)(转)
    Cocos Creator 加载使用protobuf第三方库,因为加载顺序报错
    Cocos Creator 计时器错误 cc.Scheduler: Illegal target which doesn't have uuid or instanceId.
    Cocos Creator 构造函数传参警告 Can not instantiate CCClass 'Test' with arguments.
    Cocos Creator 对象池NodePool
    Cocos Creator 坐标系 (convertToWorldSpaceAR、convertToNodeSpaceAR)
    Cocos Creator 常驻节点addPersistRootNode
    Cocos Creator 配合Tiled地图的使用
  • 原文地址:https://www.cnblogs.com/liyouming/p/9922701.html
Copyright © 2011-2022 走看看