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

.NetCore源码阅读笔记系列之Security (二) 自定义认证实践的更多相关文章

  1. .NetCore源码阅读笔记系列之Security (一) Authentication & AddCookie

    如果你使用过.NetCore开发过程序,你会很清楚,在其中我们经常会用到一些如下的代码 services.AddAuthentication(options => { options.Defau ...

  2. .NetCore源码阅读笔记系列之Security (四) Authentication & AddJwtBearer

    接下来我们在来看下AddJwtBearer,这个与AddOpenIdConnect不太一样,后者是远程发起身份认证请求是一种主动发起式的,多用于web等客户端,验证发生在身份认证服务端,而前者是一种被 ...

  3. .NetCore源码阅读笔记系列之Security (三) Authentication & AddOpenIdConnect

    通过第二篇文章我们已经知道了授权的内部实现通过自定义的授权Handler来的,同样的道理 OpenIdConnect 同样是通过 OpenIdConnectHandler来请求授权的 那么它内部又是怎 ...

  4. .NetCore源码阅读笔记系列之HttpAbstractions(五) Authentication

    说道认证&授权其实这块才是核心,这款跟前面Security这块有者紧密的联系,当然 HttpAbstractions 不光是认证.授权.还包含其他Http服务和中间价 接下来先就认证这块结合前 ...

  5. Yii源码阅读笔记(三十二)

    web/Application类的注释,继承base/Application类,针对web应用的一些处理: namespace yii\web; use Yii; use yii\base\Inval ...

  6. nsq源码阅读笔记之nsqd(二)——Topic

    与Topic相关的代码主要位于nsqd/nsqd.go, nsqd/topic.go中. Topic的获取 Topic通过GetTopic函数获取 GetTopic函数用于获取topic对象,首先先尝 ...

  7. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

  8. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  9. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

随机推荐

  1. jdk动态代理 要把目标对象 和自己都传进去;以便自己对目标对象的代理

  2. FortiGate 硬件加速

    FortiGate 硬件加速 来源 https://wenku.baidu.com/view/07749195a1c7aa00b52acb63.html 硬件加速 来源 https://blog.cs ...

  3. (转)DATATABLE(DATASET)与实体类之间的互转.

    转自:http://www.cnblogs.com/zzyyll2/archive/2010/07/20/1781649.html dataset和实体类 之间的转换 //dataset转实体类  代 ...

  4. HGOI20190126 模拟赛

    /* 最后一题比较难! */ solution:观察这个奇怪的图,不能共用走廊,就是1.2打包,3,4打包,每个包之间连线的线段覆盖问题. 考虑吧每个数映射成一个约为一半的数,且相邻(前奇后偶映射值一 ...

  5. winform程序关闭界面时弹出提示框

    void Form1_FormClosing(object sender, FormClosingEventArgs e){ if (MessageBox.Show( "窗口关闭后,数据即将 ...

  6. CF1096D Easy Problem(DP)

    貌似最近刷了好多的CF题…… 题目链接:CF原网 洛谷 题目大意:有一个长度为 $n$ 的字符串 $s$,删除第 $i$ 个字符需要代价 $a_i$.问使得 $s$ 不含有子序列(不是子串)" ...

  7. 【CC】Batman and Tree

    Portal --> CC Batman and Tree Solution 一开始看到很懵..感觉无从下手(因为自己太菜了qwq) ​ 膜拜了题解之后发现好像并没有想象的那么复杂qwq ​ 其 ...

  8. centos7下设置opencv环境变量

    最近要装YOLO,但是MAKE的时候总是找不到OPENCV的路径, 原因是:我以前卸载过一次OPENCV,然后自己重新安装了opencv2.4.10,  因为当时只在QT 中用,所以编译完也没有设置环 ...

  9. 假装会python--爬取贴吧正文

    贴吧的老历史想存下来,强行python爬取一波 队友太强,躺好别动,偶尔做点副业 假装会python 基本流程: 1.爬取页面,获取页面的html源码 2.分析源码 通过正则表达式 匹配到想要的内容 ...

  10. python的WSGI接口

    WSGI:Web Server Gateway Interface. WSGI是为python语言定义的web服务器和web应用程序或框架之间的一种简单而实用的接口.wsgi是一个web组件的接口规范 ...