asp.net core 3.x 身份验证-3cookie身份验证原理
概述
上两篇(asp.net core 3.x 身份验证-1涉及到的概念、asp.net core 3.x 身份验证-2启动阶段的配置)介绍了身份验证相关概念以及启动阶段的配置,本篇以cookie身份验证为例来大致说明asp.net core中的身份验证原理。如果我们的应用只考虑浏览器使用,且不考虑前后端分离,cookie是最简单的身份验证方式。虽然这样命名,但我们的用户标识并非一定要存到cookie里,asp.net core允许我们存储到任何地方,如:session、自定义基于内存的存储、redis等等。身份验证与asp.net core Identity结合会更简单,它提供了用户管理功能,以及更身份验证相关的辅助类,如:SignManager,不过暂时不将这东东。
还是以宏观上的理解和使用为主。主要涉及如下流程:
- 未登录时请求受保护的资源
- 登录
- 已登录时访问受保护的资源
- 注销
其中步骤1、3差别很小。总体流程大致如下图:
先在Startup中做如下配置:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication().AddCookie();
services.AddControllersWithViews();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles(); app.UseRouting();
app.UseAuthentication();
app.UseAuthorization(); app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
流程1、3、访问受保护的资源
当我们在Startup.Configre中 app.UseAuthentication(); 将注册身份验证中间AuthenticationMiddleware,它负责在请求阶段尝试从请求中获取用户标识,若获取到则赋值给HttpContext.User属性,否则以匿名用户身份继续执行下一个中间件。
AuthenticationMiddleware
流程大致如下:
- 遍历程序中所有实现IAuthenticationRequestHandler身份验证处理器,调用其HandleRequestAsync方法,此方法若返回true则终止本次请求
- 通过AuthenticationSchemeProvider获取默认身份验证方案
- 调用httpContext.AuthenticateAsync(默认方案名)尝试从请求中获取当前用户
- 如果前一步获取到用户,则设置到httpContext.User属性上
- 无论是否成功获取用户请求都会进入下一个中间件继续后续执行
步骤1中允许AuthenticationHandler在特定情况下终止请求,如果我们将来自定义AuthenticationHandler时实现IAuthenticationRequestHandler可以达到这种目的
步骤3是核心,httpContext.AuthenticateAsync是扩展方法,内部从IOC容器中获取AuthenticationService并调用其同名方法
疑惑:AuthenticationMiddleware始终获取默认身份验证方案然后尝试从请求中获取用户标识,这个默认是通过Startup.ConfigreService中 services.AddAuthentication(默认方案名) 来配置的。但一个系统中可以注册多个身份验证方案(如:同时支持Cookie和JWTBearerToken方式),所以咋处理呢?我目前能想到的是要么纯网站直接用cookie,前后端分离或移动端app默认方案设置为JWTBearerToken;另一种方式再自定义一个AuthenticationMiddleware;但是感觉都很别扭,所以你有好的想法请指教下,不胜感激!
AuthenticationService.AuthenticateAsync
大致执行如下步骤:
- 通过AuthenticationHandlerProvider(注入进来的)获取指定(这里就是默认的)身份验证方案名获取关联的身份验证处理器AuthenticationHandler
- 调用AuthenticationHandler.AuthenticateAsync()尝试从请求中获取用户
- 返回前尝试将用户标识转换成另一个用户标识(且进行缓存,由于AuthenticationService是Scope注册的,所以没问题)
步骤2针对Cookie身份验证来说最终体现为CookieAuthenticationHandler.HandleAuthenticateAsync()
步骤3在将用户标识设置到httpContext.User之前允许我们添加修改用户标识的某些数据。实现方式是定义类实现IClaimsTransformation并将其(推荐单例)注册到依赖注入容器。
CookieAuthenticationHandler.HandleAuthenticateAsync
大致流程如下:
- 通过Options.CookieManager获取cookie
- 若Options.SessionStore不为空则从其获取票证,否则直接解密cookie得到票证
- 处理票证过期(如Option设置了滑动过期,在过期时响应时重新将票证写入cookie)
- 回调Events.ValidatePrincipal允许我们修改或替换用户标识
上述步骤多次用到了Options,它是CookieAuthenticationOptions类型的,专门针对基于cookie的身份验证处理器的选项对象,参考:《asp.net core 3.x 身份验证-2启动阶段的配置》,此选项对象的默认赋值行为在PostConfigureCookieAuthenticationOptions.PostConfigre中定义,我们也可以在启动配置时进行定制,
比如我们想直接将票证存储到自定义的存储中时可以参考下面的配置:
- 自定义一个类实现ITicketStore(参考)
- 配置cookie身份验证方案时修改选项 services.AddAuthentication().AddCookie(opt=> opt.SessionStore = new MySessionStore());
在CookieAuthenticationHandler的其它多个步骤中都可能使用到此选项对象。使用方式都类似。
在前一步骤AuthenticationService.AuthenticateAsync的步骤3中允许我们的代码替换/修改用户标识,在这里的步骤4也允许做类似的事,区别在于前者是针对所有身份验证方案有效的,如默认身份验证方案为JwtBeaerToken时也有效。而后者只是针对cookie身份验证有效。
AuthorizationMiddleware
由于首次请求用户尚未登录,所以context.User为空。授权中间件最终会执行 context.ChallengeAsync(); 最终会执行CookieAuthenticationHandler.HandleChallengeAsync
CookieAuthenticationHandler.HandleChallengeAsync
默认大致流程如下:
- 组织登录页地址:Options.LoginPath + QueryString.Create(Options.ReturnUrlParameter, 当前地址);
- 回调Events.RedirectToLogin,若是ajax请求则返回401状态码,否则跳转到登录页
默认登录页地址"/Account/Login",参考PostConfigureCookieAuthenticationOptions.PostConfigre默认处理流程如下:
public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToLogin { get; set; } = context =>
{
if (IsAjaxRequest(context.Request))
{
context.Response.Headers[HeaderNames.Location] = context.RedirectUri;
context.Response.StatusCode = ;
}
else
{
context.Response.Redirect(context.RedirectUri);
}
return Task.CompletedTask;
};
我们也可以通过在应用启动时通过选项对象来修改。
services.AddAuthentication().AddCookie(opt =>
{
opt.LoginPath = "account/mylogin";
opt.Events.OnRedirectToLogin = context =>
{
context.Response.Redirect(context.RedirectUri);
return Task.CompletedTask;
};
});
流程2、登录
前端提交用户名密码,Action去数据库对比,若成功则以用户id(或一些非常常用的和与授权相关的属性)作为用户标识。然后调用HttpContext.SignInAsync(ClaimsPrincipal),所以最终会执行CookieAuthenticationHandler.HandleSignInAsync
CookieAuthenticationHandler.HandleSignInAsync
大致步骤如下:
- 准备一个CookieSigningInContext(=当前上下文+当前身份验证方案+当前身份验证方案关联的选项对象+需要登录用户的标识+cookie选项+额外数据)
- 处理过期时间等属性
- 回调Events.SigningIn,允许我们在写入cookie之前做调整
- 准备票证(=用户 + 身份验证相关属性 + 身份验证方案名 )
- 若此身份验证处理器对应的选项配置了Options.SessionStore则使用此存储,否则加密票证写入cookie
- 回调Events.SignedIn
- 最后回调Events.RedirectToReturnUrl尝试调整会最初的访问页面
流程4、注销
在Action中调用Context.SingOutAsync可以实现注销,在为传入方案名的情况下使用默认身份验证方案进行注销,假设默认是cookie身份验证,则CookieAuthenticationHandler.HandleSignOutAsync将被执行。大致流程如下:
若选项对象配置了Options.SessionStore则从其清空用户标识
回调Events.SigningOut
清除cookie(可能是含sessionKey或包含用户标识的cookie)
通过回调Events.RedirectToReturnUrl跳转到Options.ReturnUrlParameter页面
总结
本篇只是从大方向说了下基于cookie的身份验证原理,对于我们开发者来说只要记住如下几个点就行了,将来有特殊需求时再去看源码。
- 应用启动时Startup中通过AddAuthencation(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(opt=>{ 配置各种选项/不配置直接使用默认值 });Configure方法中app.UseRouting();后app.UseAuthentication();插入身份验证中间件
- opt是CookieAuthenticationOptions类型,我们可以通过它来参与到身份验证的过程中去,记得它有个回调函数集合Events属性。这个选项对象的默认值定义在PostConfigureCookieAuthenticationOptions.PostConfigre、CookieAuthenticationDefaults,Events属性的类型和默认值参考CookieAuthenticationEvents
- 通常我们调用身份验证方法是通过HttpContext来调用,它会从IOC容器拿到AuthenticationService调用其同名方法,最终会找到合适的AuthenticationHandler并调用其同名方法
暂时就想到这么多,以后想到再补充吧。
asp.net core 3.x 身份验证-3cookie身份验证原理的更多相关文章
- 如何在ASP.NET Core中实现一个基础的身份认证
注:本文提到的代码示例下载地址> How to achieve a basic authorization in ASP.NET Core 如何在ASP.NET Core中实现一个基础的身份认证 ...
- [转]如何在ASP.NET Core中实现一个基础的身份认证
本文转自:http://www.cnblogs.com/onecodeonescript/p/6015512.html 注:本文提到的代码示例下载地址> How to achieve a bas ...
- ASP.NET Core WebApi基于JWT实现接口授权验证
一.ASP.Net Core WebApi JWT课程前言 我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再 ...
- Asp.Net Core 5 REST API 使用 JWT 身份验证 - Step by Step
翻译自 Mohamad Lawand 2021年1月22日的文章 <Asp Net Core 5 Rest API Authentication with JWT Step by Step> ...
- ASP.NET Core 如何用 Cookie 来做身份验证
前言 本示例完全是基于 ASP.NET Core 3.0.本文核心是要理解 Claim, ClaimsIdentity, ClaimsPrincipal,读者如果有疑问,可以参考文章 理解ASP.NE ...
- 用Middleware给ASP.NET Core Web API添加自己的授权验证
Web API,是一个能让前后端分离.解放前后端生产力的好东西.不过大部分公司应该都没能做到完全的前后端分离.API的实现方式有很 多,可以用ASP.NET Core.也可以用ASP.NET Web ...
- [转]用Middleware给ASP.NET Core Web API添加自己的授权验证
本文转自:http://www.cnblogs.com/catcher1994/p/6021046.html Web API,是一个能让前后端分离.解放前后端生产力的好东西.不过大部分公司应该都没能做 ...
- 在 ASP.NET Core 应用中使用 Cookie 进行身份认证
Overview 身份认证是网站最基本的功能,最近因为业务部门的一个需求,需要对一个已经存在很久的小工具网站进行改造,因为在逐步的将一些离散的系统迁移至 .NET Core,所以趁这个机会将这个老的 ...
- 【ASP.NET Core】使用最熟悉的Session验证方案
如果大伙伴们以前写过 ASP 或 PHP 之类的,相信各位对基于 Session 的身份验证很熟悉(其实在浏览器端是结合 Cookie 来处理的).这种验证方式是比较早期的,操作起来也不复杂. a.用 ...
随机推荐
- webpack4的配置你都掌握了么?
webpack5都出了,webpack4的的基本配置,解析ES6,引入CSS,编译Less,设置image等等,你都会了么? 解析ES6 了解Babel Babel是一个JavaScript编译器, ...
- zabbix安装和使用
前言:zabbix是一款很好用的监控工具,相比nagios(也是监控工具的一种)而言,zabbix提供了强大的视图界面,操作简单,功能强大,只需在页面配置即可,让你用的开心,回家放心. zabbix监 ...
- linux入门系列5--新手必会的linux命令
上一篇文章"linux入门系列4--vi/vim编辑器"我们讨论了在linux下如何快速高效对文本文件进行编辑和管理,本文将进一步学习必须掌握的linux命令,掌握这些命令才能让计 ...
- 重拾c++第一天(3):数据处理
1.short至少16位:int至少与short一样长:long至少32位,且至少与int一样长:long long至少64位,且至少与long一样长 2.sizeof 变量 返回变量长度 或者s ...
- Mysql连接出现时区问题
错误提示: The server time zone value '¥x¥_¼Ð·Ç®É¶¡' is unrecognized or represents more than one time zon ...
- 理解setTimeout()
之前在网上看了很多关于setTimeout的文章,但我感觉都只是点到为止,并没有较深入的去剖析,也可能是我脑袋瓜笨,不容易被点解.后面看了<你不知道的javascript-上卷>一书,决定 ...
- MySQL8.0.19安装
官网下载安装包:mysql-8.0.19-linux-glibc2.12-x86_64.tar.xz 安装环境:CentOS Linux release 7.5.1804 (Core) 解压安装包: ...
- [bzoj4447] [loj#2010] [Scoi2015] 小凸解密码
Description 小凸得到了一个密码盘,密码盘被等分成 \(N\) 个扇形,每个扇形上有一个数字(0-9),和一个符号("+"或"*") 密码盘解密的方法 ...
- 2、pycharm安装及相关配置
PyCharm是一种Python IDE,带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试. 语法高亮.Project管理.代码跳转.智能提示.自动完成.单元测试.版本控制 ...
- Sublime Text 3 安装包
摘要 Error while loading PyV8 binary:exit code 3 .sublime-package报错 安装SublimeREPL,可以运行python代码 安装local ...