首页 > 编程语言 >.NetCore源码阅读笔记系列之Security (二) 自定义认证实践

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

时间:2024-05-22 23:22:30浏览次数:39  
标签:Task return 自定义 NetCore builder 源码 context new public

通过前面对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,这个时候处理认证信息 ,最后也没没有输出

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!
本文版权归作者和博客园共有,来源网址:http://www.cnblogs.com/liyouming欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接
     

标签:Task,return,自定义,NetCore,builder,源码,context,new,public
From: https://www.cnblogs.com/webenh/p/18207342

相关文章

  • WordPress标签实现追加自定义链接
    WordPress标签的用处说多不多,说少不少,其中利用WordPress标签做聚合页面优化是一种搜索引擎很喜欢的方式,或者说很多搜索引擎相比正文页面而言更喜欢抓取和收录标签页面,其次对于WordPress标签的作用就是用于文章关键词调用以及文章内链。那么今天子凡我我将利用几行代码来实......
  • js 创建和触发事件 和 自定义事件
    1、创建自定义事件Eventconstevent=newEvent("build");//监听该事件。elem.addEventListener("build",(e)=>{/*…*/},false,);//分派该事件。elem.dispatchEvent(event);2、创建自定义事件&添加自定义数据——customevent事件挂在到win......
  • openAI assistants的自定义函数调用——类似HiAgent
    openAIassistants的自定义函数调用功能先添加函数: 和字节的hiagent非常相似。定义好函数以后。然后就是在客户端通过如下代码调用:  #读取系统变量fromdotenvimportload_dotenvload_dotenv()fromopenaiimportOpenAI#初始化客户端client=OpenAI()......
  • containerd 源码分析:kubelet 和 containerd 交互
    0.前言Kubernetes:kubelet源码分析之创建pod流程介绍了kubelet创建pod的流程,其中介绍了kubelet调用runtimecri接口创建pod。containerd源码分析:启动注册流程介绍了containerd作为一种行业标准的高级运行时的启动注册流程。那么,kubelet是怎么和containerd......
  • 基于WPF+Sqlite开发抽奖软件【内附源码】
    在很早之前,就想过开发一款抽奖软件,却一直没有实际去做,最近经过一段时间的准备,终于开发出了一款基于WPF+Sqlite版的抽奖软件,包括客户端和管理端。本项目主要是为了熟悉WPF开发流程,仅供学习分享使用,如有不足之处,还请指正。 涉及知识点 抽奖软件是包括客户端和管理端,在抽奖软件......
  • 摸清自定义流程表单开发优点 实现降本增效!
    随着社会竞争压力的增大,很多企业都希望实现降本增效提质的办公效果。那么,借助什么样的软件平台可以让企业在提升市场竞争力的前提下,还能降低开发成本,提高成效?低代码技术平台是目前流行于中小企业办公职场中的平台产品,其中自定义流程表单开发优势特点多、灵活高效、可视化操作界面,......
  • 【unity】在EditorWindow添加自定义的Toolbar按钮
    好久没写了,最近做工具,写了个EditorWindow,为了让使用者方便查看这个工具的文档,想着在导航栏加个问号按钮,点一下打开说明文档就完事~查了下unity手册,发现Unity提供了一个ShowButton 方法,用于在自定义Editor窗口的工具栏中添加自定义内容,下面是实现的例子:privateGUIStyle......
  • duilib 自定义控件
    1.主窗口自定义FramWnd继承WindowImplBase,重写CreateControl,HandleMessage.组合CPaintManagerUI.2.自定义控件自定义mycontrol继承CControlUI重写DoEvent,DoPaint,SetPos.main.cpp#include"FramWnd.h"intAPIENTRYWinMain(HINSTANCEhInstance,HINSTANCE/*hPrev......
  • Python:自定义类或模块时的注意事项
     Python进阶版:定义类时应用的9种最佳做法1.好的命名2.显式实例属性3.使用属性——但要精简4.定义有意义的字符串表示法5.实例方法,类方法和静态方法6.使用私有属性进行封装7.分离关注点和解耦8.考虑使用__slots__进行优化9.文件 1.好的命名定义自己的类,就......
  • keycloak~自定义认证流设置固定redirect_uri
    redirect_uri在keycloak进行认证成功之后,会重定向到这个目标页面,一般为用户的来源页,即你在登录之前访问的页面;自定义认证流是指对keycloak中的brower和directgrant两个认证方式的过程添加自定义策略,如在用户登录成功时,检查它的密码强度,如果不符合要求,就跳到一个说明页面,告诉用户,......