Identity – Without Identity Framework
前言
上一回研究 Authenticate 和 Authorization 已经是 2 年前了.
业务需求一直没有增长, 所以也没有再去提升它了. 但最近业务开始上去了. 荒废的功夫又得拾起来了.
上一回我没有耐心写完 IdentityServer4 和 Angular. 这回希望能写完它. 不打算修改之前的了. 从头开始吧.
这 2 年微软的文档做的越来越好了. 这里就按着文档做一遍 warm up + summary 就好呗.
这个系列会涉及到的技术是:
Razor Pages,
Web API,
Identity,
OpenIDDict Core (thrid party for OIDC + OAuth, 我没有使用 IdentityServer4 了),
Angular
介绍
Authentication (authen) 主要讲的就是登入, 身份验证,
Authorization (autho) 讲的是权限, 登入不表示拥有所有权限. 可以算是 2nd level protection.
用 ASP.NET Core 做 authen 一般上都会用 Identity Framework 插件 (build-in 的), 然后在插件上做一些魔改. 比较少从 0 开始写,
但其实 ASP.NET Core 底层是有一些基础功能的, 它可以让我们从 0 开始写. 这篇主要就是讲这一块.
主要参考
参考: Use cookie authentication without ASP.NET Core Identity
Protect Page
新建一个项目
dotnet new webapp -o WithoutIdentity
在 privacy page 加上 [Authorize] 标签.
Privacy.cshtml.cs
[Authorize]
public class PrivacyModel : PageModel
{
public void OnGet()
{
}
}
这个时候, 访问这个页面的话就会报错了, 因为我们还没有做任何 authen 的配置.
Setup Config
现在去 Program.cs, 添加配置
builder.Services
.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
Schemes 是方案的意思, 比如 Cookies Schemes, JWT Schemes 等等
CookieAuthenticationDefaults.AuthenticationScheme 是一个 string, 就是方案的名字. AddAuthentication 声明默认使用什么方案.
AddCookie 则是 ASP.NET Core 封装好的一个 Cookie 方案. 这也是最常见的方案, 参数是方案的名字.
另外, 还有一个常见的方案是 JWT (JSON Web Token), 采用前后端分离架构, 通常就会使用这个方案.
JWT 需要安装
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
配置
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
services 配置好后就到 middleware.
添加一个 app.UseAuthentication()
注: 位置要对哦.
这时再访问 private page 出现的 error 就不一样了. 它会 redirect 到 Account/Login page.
这个是 default login page 的路径.
参考: CookieAuthenticationDefaults.cs
我们可以通过 options 来修改掉 login path, 还有其它 Cookie 相关的配置.
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => {
options.Cookie.Name = "MyCookieName";
options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict;
options.ReturnUrlParameter = "returnUrl";
options.LoginPath = "/login";
options.LogoutPath = "/logout";
options.AccessDeniedPath = "/access-denied";
});
注: SameSiteMode 默认是 Lax, Lax 级别已经足够我们做 OAuth 了. 所以不需要 set 成 Strict (我只是演示而已)
相关参考:
Work with SameSite cookies in ASP.NET Core
Login Page
接下来, 我们做一个 login page.
当 user 被 redirect 到 login page 时, URL query 会附上一个 returnUrl, 它记入 user 是从哪一个路径被 redirect 过来的. 当登入成功, 我们可以让 user redirect 回去.
在这个 login page 做一个 login button post
public async Task OnPostAsync([FromQuery] string returnUrl)
{
var claimsIdentity = new ClaimsIdentity(new List<Claim> {
new Claim(ClaimTypes.Name, "UserName")
}, CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
new AuthenticationProperties()
);
}
HttpContext.SignInAsync 是 ASP.NET Core 封装好的方法.
参数 1 是方案的名字,
参数 2 是 Principal, 里面的 claims 是用来做 authorization 的 (最少都要有一个 Name 的 claims, 而已必须是 unique)
参数 3 是 authentication properties 比如 remenber me 之类的配置.
我们不需要做额外写逻辑去 redirect, SignInAsync 会帮我们 redirect to returnUrl
完成后就成功进入 privacy page 了, 上图是 login 后 response cookie, 它的 value 是用 data protection 加密过的哦.
Logout Page
接着做一个 logout page
public async Task OnPostAsync()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
}
然后在任何想 logout 的 page 里面写一个 form, post 去 logout page, 并且附上 returnUrl
<form asp-page="/Account/Logout/Index" asp-route-returnUrl="/" method="post">
<button type="submit">Click here to Logout</button>
</form>
这里有一篇对 logout path 的解释: What does the CookieAuthenticationOptions.LogoutPath property do in ASP.NET Core 2.1?
我本来以为 logout path 的意思是你 logout 完成后它会跳转到这个 page
其实不是这样的. 它有点像 login page 是用来做 logout 的. 当调用 SignOutAsync 时, 当前的 path 必须是 options.LogoutPath (我们在 AddCookie 时写进去的) 那么才会触发 redirect
参考一下 Identity Framework 的实现, 这个是 logout button 可以放在任何地方. 它会 post to /Account/Logout page 附上了 returnUrl.
然后 /Account/Logout.cs 是这样
估计 SignInManger.SignOutAsync 里头就调用了 HttpContext.SignOutAsync.
React to back-end changes
这个概念蛮重要的, 之前我也是没有搞明白.
首先要知道, cookie 保存了 user info, 通过 data protection 对称加密来保护.
在验证的时候, 直接解密成功就登入了. 这个流程是不走数据库的.
好处是快, 坏处就是无法即刻注销这个 cookie. 比如说用户换了密码, 他的预想是之前的 cookie 应该就失效了. 但是没有.
那怎么办呢? 微软把这个权衡留给我们决定。
Identity Framework 对此的方案叫 Security Stamp, 它的做法是. 设定一个检测时期, 比如默认是超过 30 分钟就得去数据库检查一次.
检查什么呢? 就是 security stamp 是否和之前一样. 如果一样就表示这段期间用户并没有做出任何会影响到授权的事. 如果有那么就应该要 update 这个 security stamp. 那么期限一到, 检查的时候就会发现.
Identity Framework 检查的时候会跑 5 个 select from table, 性能还是蛮伤的呢.
可以通过 config 去 set 检测的间隔时间
services.Configure<SecurityStampValidatorOptions>(o => {
o.ValidationInterval = TimeSpan.FromSeconds(60);
});
说太多 Identity Framework 了, 讲回 without Identity Framework 的情况下, 它是怎样 work 的
首先是做 principal 的时候放多一个 security stamp claim
然后在 AddCookie 的时候放入一个 Events 拦截
继承 CookieAuthenticationEvents 然后 override 掉 ValidatePrincipal, 里头就可以检查然后 reject 之类的
或者像 identity 这样配置也是可以的
具体 validation 是这样的
判断时间 > 数据库检查 > 不通过就 signout > 通过就 replace principal, replace principal 不是 identity 的功能, 而是 ASP.NET Core 的功能.
Cookie Expires
refer: How to set asp.net Identity cookies expires time
有几个东西跟 expires 息息相关
SlidingExpiration = 这个是说 keep renew cookie, 每次 request 来的时候如果 cookie 是 ok 的 then 就续命.
Persistent = 如果是 false 的话, 那么就是没有 remember me, cookie expires 是 session, 如果是 true 那么 expires 就 base on cookie option 的 ExpireTimeSpan (默认 14 天)
在 SignIn 的时候还可以调绝对过期 ExpiresUtc 它会覆盖掉 option 的 ExpireTimeSpan, 也不会理会 SlidingExpiration 了 (set 绝对的时候要 Persistent true 哦, 因为 false 就是跑 session)
Cookie expires session 就是说当 browser close 它就被清掉. 需要留意的是 chrome, 一但你 set 了 continue where you left off 它就不会清除掉 expires session cookie 了. 即使是你 off pc 也不会...
Identity – Without Identity Framework的更多相关文章
- 第63章 ASP.NET Identity 支持 - Identity Server 4 中文文档(v1.0.0)
提供了基于ASP.NET身份的实现,用于管理IdentityServer用户的身份数据库.此实现是IdentityServer中的扩展点,以便为用户加载身份数据以将声明发送到令牌. 这个支持的仓储位于 ...
- Asp.Net.Identity认证不依赖Entity Framework实现方式
Asp.Net.Identity为何物请自行搜索,也可转向此文章http://www.cnblogs.com/shanyou/p/3918178.html 本来微软已经帮我们将授权.认证以及数据库存储 ...
- VS2013中web项目中自动生成的ASP.NET Identity代码思考
vs2013没有再分webform.mvc.api项目,使用vs2013创建一个web项目模板选MVC,身份验证选个人用户账户.项目会生成ASP.NET Identity的一些代码.这些代码主要在Ac ...
- ASP.NET Identity 简介
翻译自:http://www.asp.net/identity/overview/getting-started/introduction-to-aspnet-identity ,略有改动. 背景:A ...
- ASP.NET Identity系列教程(目录)
$(document).ready(function(){ $("#hide").click(function(){ $(".en").hide(); }); ...
- ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇
在之前的文章中,我为大家介绍了OWIN和Katana,有了对它们的基本了解后,才能更好的去学习ASP.NET Identity,因为它已经对OWIN 有了良好的集成. 在这篇文章中,我主要关注ASP. ...
- 【ASP.NET Identity系列教程(一)】ASP.NET Identity入门
注:本文是[ASP.NET Identity系列教程]的第一篇.本系列教程详细.完整.深入地介绍了微软的ASP.NET Identity技术,描述了如何运用ASP.NET Identity实现应用程序 ...
- 自定义表并实现Identity登录(一)
注意,Microsoft.AspNet.Identity.Core.1.0.0和Microsoft.AspNet.Identity.Core.2.2.1差别太大,需考虑实际项目中用的是哪种,本文是基于 ...
- ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇(转)
ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇 阅读目录 ASP.NET Identity 前世今生 建立 ASP.NET Identity 使用ASP.NET ...
- 转载 ASP.NET MVC中使用ASP.NET Identity
转载原地址: http://blog.jobbole.com/90695/ 在之前的文章中,我为大家介绍了OWIN和Katana,有了对它们的基本了解后,才能更好的去学习ASP.NET Identit ...
随机推荐
- 解决方案 | cvxpy成功安装过程及其使用攻略
背景: 由于需要研究KKT条件下的最优化问题,需要安装一个python的包cvxpy. 过程: 1.正常pip install cvxpy 不可取(不会成功,中间有报错): 2.主要错误在于:其依赖 ...
- OffscreenCanvas-离屏canvas使用说明
OffscreenCanvas 是一个实验中的新特性,主要用于提升 Canvas 2D/3D 绘图的渲染性能和使用体验.OffscreenCanvas 的 API 很简单,但是要真正掌握好如何使用. ...
- 基于Java+Spring+Vue仓储出入库管理系统设计和实现
\n文末获取源码联系 感兴趣的可以先收藏起来,大家在毕设选题,项目以及论文编写等相关问题都可以给我加好友咨询 系统介绍: 网络的广泛应用给生活带来了十分的便利.所以把仓储出入库管理与现在网络相结合,利 ...
- CSS:弹性布局(display:flex)
道友请了~ 最近小道在修练主修功法<嘉蛙>之余,偶然从一名散修手中得到了一本<CSS秘籍>,刚好近期有自己做微信小程序的打算,这不是瞌睡了给递枕头么.欣喜若狂,翻开第一章,拜读 ...
- 面试题-python 什么是闭包(closure)?
前言 前面学了装饰器,那么闭包和装饰器有什么区别呢?闭包传递的是变量,而装饰器传递的是函数对象,只是传的参数内容不一样,闭包的概念包含了装饰器,可以说装饰器是闭包的一种,它只是传递函数对象的闭包. 先 ...
- 文件系统(十一):Linux Squashfs只读文件系统介绍
liwen01 2024.07.21 前言 嵌入式Linux系统中,squashfs文件系统使用非常广泛.它主要的特性是只读,文件压缩比例高.对于flash空间紧张的系统,可以将一些不需要修改的资源打 ...
- 【Vue】二维码生成
按组长提供的样例,功能比较相符合的是这个博客: https://www.jianshu.com/p/8d59107e1992 这个博客引用的是这篇文章: https://blog.csdn.net/w ...
- 【C】Re02
一.命令行参数 #include <stdio.h> /** * 运行执行程序的命令携带 一些附加参数,传递给程序执行 * @param argc 命令行参数的个数 * @param ar ...
- 外形最漂亮的人形机器人——通用机器人Apollo,设计为可以在任何任务和环境中与人类进行协作
视频地址: https://www.bilibili.com/video/BV11F4m1M7ph/
- Inno Setup 出现 the drive or unc share you selected does not exist or is not accessible 解决记录
背景 软件是使用Inno Setup的,且安装后,再次安装是默认安装到历史路径.一次用户电脑维修后,发现再次安装后报错 解决办法 取消自动安装到默认路径就好了~ UsePreviousAppDir=n ...