.NetCore源码阅读笔记系列之Security (一) Authentication & AddCookie
如果你使用过.NetCore开发过程序,你会很清楚,在其中我们经常会用到一些如下的代码
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie("Cookies",options=>{
});
然后添加了中间件
app.UseAuthentication();
然而这些中间内部、服务之间怎么去处授权的呢?接下来就来探讨一下。
先来说说UseAuthentication这个都做了什么事情
首先我们先来看下在判断授权的时候是用HttpContext.User中获取了身份信息,从身份中获取了IsAuthenticated来判断是否认证,通过这些我们发现其实 UseAuthentication就做了下面的事情,通过app.UseMiddleware<AuthenticationMiddleware>();中间件将身份信息写入到上下文对象中的User中
context.User = result.Principal;
不然发现在这个过程中,会有一些相关的基础服务和配置参数,让后自然而然会想到添加注入服务,然后下面的代码就出来了,添加认证服务、以及一些初始参数的配置
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
接下来我们来看一看AddAuthentication干了什么事情,写过扩展的朋友都知道,AddAuthentication只是一个挂载到IServiceCollection上的一个扩展方法,有参数就想到了配置所里扩展方法里面就完成了2件事情
var builder = services.AddAuthentication();
services.Configure(configureOptions);
添加授权服务和添加配置服务
这里的builder其实是AuthenticationBuilder,其实这个类也没做什么事情,就接管了下IServiceCollection服务,以便于在AuthenticationBuilder中完成对services服务调用完成其他的功能,如AddScheme
public AuthenticationBuilder(IServiceCollection services)
=> Services = services;
管道中中间件像企业的生产流水线一样,经过一层一层的加工(HttpContext=>HttpRequest、HttpRespose、IFeatureCollection、ClaimsPrincipal)等,最后返回加工好的产品,这里的认证中间件也不例外,主要就是为了附加ClaimsPrincipal而生的
这个图也不知被用了多少次了,我也用下
接下来就来看下在中间件AuthenticationMiddleware中都做了什么事情
public static IApplicationBuilder UseAuthentication(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
} return app.UseMiddleware<AuthenticationMiddleware>();
}
说道中间件不得不提到一个重要的东东RequestDelegate这个对象,他就想一个包裹的产品,穿梭连接在每个中间件游走,就想生产流水线上的传送产品的传送带一样,传送做请求中的各种对象
首先要获取的就是 提供的认证处理服务 IAuthenticationHandlerProvider
var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
这里还要说下的就是IAuthenticationSchemeProvider,由于授权参数指定的Scheme指定了获取授权来源,中间件需要获取当前配置的Scheme对应的IAuthenticationHandlerProvider处理服务
如果获取到就处理认证请求,这里要说明下代码,在.NetCore其他地方对下面处理请求做了接口实现,其实就是AddCookies中的CookieAuthenticationHandler,当找到对应请求就不会在处理了。
public interface IAuthenticationRequestHandler : IAuthenticationHandler
{ Task<bool> HandleRequestAsync();
}
可以看到这样的实现,需要什么实现就添加什么handle,只是这里AddCookie帮我们处理了
public class CookieAuthenticationHandler :
AuthenticationHandler<CookieAuthenticationOptions>,
IAuthenticationSignInHandler,
IAuthenticationSignOutHandler
{ }
如果没有从授权Scheme中找到,说明未认证,需要添加认证身份信息的Scheme,获取到IAuthenticationService服务
context.RequestServices.GetRequiredService<IAuthenticationService>().AuthenticateAsync(context, scheme);
这里实际上还是从IAuthenticationHandlerProvider服务提供,只是在IAuthenticationService服务中注入了相关服务,最终还是通过IAuthenticationHandler去实现的
public AuthenticationService(IAuthenticationSchemeProvider schemes, IAuthenticationHandlerProvider handlers, IClaimsTransformation transform)
{
/* */
}
那么登录的时候SignIn做了什么呢?
context.RequestServices.GetRequiredService<IAuthenticationService>().SignInAsync(context, scheme, principal, properties);
从认证服务中调用了SignIn,其实最终都是通过IAuthenticationHandler接口来处理的,SignIn、SignOut都是通过AddCookies中CookieAuthenticationHandler通过实现了IAuthenticationSignInHandler来处理,退出IAuthenticationSignOutHandler,认证则是实现IAuthenticationHandler接口,下面我们针对上面的来画图分析下可能要明白一些
下面在来看下AddCookie都做了什么
public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<CookieAuthenticationOptions> configureOptions)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureCookieAuthenticationOptions>());
return builder.AddScheme<CookieAuthenticationOptions, CookieAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
}
这里添加好了Scheme信息,而在AddScheme中注册了CookieAuthenticationHandler服务,在这里服务中我们可以看到一个返回认证信息的一个重写方法,而最终处理认证的就是这个处理,它继承了AuthenticationHandler<Options>,而在AuthenticationHandler里面去实现了IAuthenticationHandler (Task<AuthenticateResult> AuthenticateAsync()),这个之前说的认证具体实现,下面这个是在 AuthenticationHandler<Options> [protected abstract Task<AuthenticateResult> HandleAuthenticateAsync()] 抽象重写,实际这个就是在IAuthenticationHandler (Task<AuthenticateResult> AuthenticateAsync())中来实现的
protected abstract Task<AuthenticateResult> HandleAuthenticateAsync();
public async Task<AuthenticateResult> AuthenticateAsync()
{ var result = await HandleAuthenticateOnceAsync();
/*.....*/return result;
}
protected Task<AuthenticateResult> HandleAuthenticateOnceAsync()
{
if (_authenticateTask == null)
{
_authenticateTask = HandleAuthenticateAsync();
} return _authenticateTask;
}
HandleAuthenticateAsync 被CookieAuthenticationHandler 重写,后通过一些列处理返回了认证结果信息
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
/*
Handle略
*/
return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name));
}
如此类推,总结如下:
AddCookies只是为IAuthenticationHandlerProvider中提供认证服务的来源做工作,所有会有 AddOpenIdConnect、AddJwtBearer、AddWsFederation 以及第三方扩展的 Facebook 、Google、OAuth等等
.NetCore源码阅读笔记系列之Security (一) Authentication & AddCookie的更多相关文章
- .NetCore源码阅读笔记系列之Security (二) 自定义认证实践
通过前面对AddCookie 或者 AddOpenIdConnect 等了解,其实里面都实现了一个AuthenticationHandler<TOptions>的认证处理,接下来我们来简单 ...
- .NetCore源码阅读笔记系列之Security (四) Authentication & AddJwtBearer
接下来我们在来看下AddJwtBearer,这个与AddOpenIdConnect不太一样,后者是远程发起身份认证请求是一种主动发起式的,多用于web等客户端,验证发生在身份认证服务端,而前者是一种被 ...
- .NetCore源码阅读笔记系列之Security (三) Authentication & AddOpenIdConnect
通过第二篇文章我们已经知道了授权的内部实现通过自定义的授权Handler来的,同样的道理 OpenIdConnect 同样是通过 OpenIdConnectHandler来请求授权的 那么它内部又是怎 ...
- .NetCore源码阅读笔记系列之HttpAbstractions(五) Authentication
说道认证&授权其实这块才是核心,这款跟前面Security这块有者紧密的联系,当然 HttpAbstractions 不光是认证.授权.还包含其他Http服务和中间价 接下来先就认证这块结合前 ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...
- CI框架源码阅读笔记5 基准测试 BenchMark.php
上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...
- CI框架源码阅读笔记3 全局函数Common.php
从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...
- CI框架源码阅读笔记2 一切的入口 index.php
上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...
- 源码阅读笔记 - 1 MSVC2015中的std::sort
大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...
随机推荐
- 51nod 1476 括号序列的最小代价(贪心+优先队列)
题意 我们这有一种仅由"(",")"和"?"组成的括号序列,你必须将"?"替换成括号,从而得到一个合法的括号序列. 对于 ...
- LOJ #2141. 「SHOI2017」期末考试
题目链接 LOJ #2141 题解 据说这道题可以三分(甚至二分)? 反正我是枚举的 = = 先将t和b数组排序后计算出前缀和, 然后枚举最晚的出成绩时间,每次可以O(1)直接计算调整到该时间所需的代 ...
- HGOI20180817 (NOIP模拟Day1 task)
HGOI自测 初测:150=80+20+50 rank1~rank3(并列3个rank1,所以我是rank3 qwq) 今日分突然想简约 CF359A Table https://www.luogu. ...
- 在Mac上配置全局的Git忽略文件
现在同时搞着好几个项目,在Xcode.IDEA.Eclipse之间频繁的切换,每个项目的忽略文件列表都不一样,每个项目都有一个.gitignore,甚是麻烦,今天网上拔出来一个设置全局忽略的办法,记录 ...
- PyQt4 安装
安装PyQt4很简单,从官网下载相应的安装包即可. 需要注意的是:应该根据你电脑上已经装好的python版本选择相应的PyQt4安装包. PyQt4的安装目录一定要选python的安装目录,比如我的P ...
- codeblocks调试
1.Next instruction 逐指令 (有可能一行内有多条指令) (Alt+F7) Next line 逐行(有可能一条指令分成多行) (F7) Next instruction: -> ...
- arcgis创建渔网
创建渔网 1. ArcToolbox > Data Management Tools > Feature Class > Create Finshnet.选择输出要素位置,模 ...
- 【CSS】clear清除浮动
clear清除浮动1.作用: 规定元素的某一侧不允许存在浮动元素 2.值: 3.应用: 清除其他浮动元素对其产生的影响 <!DOCTYPE html> <html lang=&quo ...
- 一些常见修改命令(针对ubuntu 14.04 持续更新中...)
1.PS1 在哪: echo $PS1 vi /etc/bash.bashrc /W输出最后一个目录 /w输出完整目录 2.设置静态IP地址:vim /etc/network/i ...
- JVM内存管理---垃圾收集器
说起垃圾收集(Garbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物.事实上,GC的历史远比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态 ...