ASP.NET Core 之 Identity 入门(二)

前言

在 上篇文章 中讲了关于 Identity 需要了解的单词以及相对应的几个知识点,并且知道了Identity处在整个登入流程中的位置,本篇主要是在 .NET 整个认证系统中比较重要的一个环节,就是 认证(Authentication),因为想要把 Identity 讲清楚,是绕不过 Authentication 的。

在之前写过一篇关于 ASP.NET Core 中间件的文章,里面有一部分(怎么样自定义自己的中间件)是具体关于认证系统的一个具体使用,有兴趣的朋友可以看一下这篇文章。

其实 Identity 也是认证系统的一个具体使用,大家一定要把 Authentication 和 Identity 当作是两个东西,一旦混淆,你就容易陷入进去。

下面就来说一下 ASP.NET Core 中的认证系统是怎么样一回事。不要怕,其实很简单,全是干货~

Getting Started

大家应该还记得在上一篇中的奥巴马先生吧,他现在不住在华盛顿了,他到中国来旅游了,现在住在北京,这几天听说西湖风景不错,于是在 12306 定了一张北京到杭州的高铁票。取到票之后,他向我们展示了一下:

今天是11.11号,奥巴马很开心,原因你懂的。快到出发的时间了,于是,拿着票走到了火车站检票口,刚把身份证和火车票递给检票员。“cut”,导演喊了一声。尼玛原来是在拍电影呢~
导演说:奥巴马,你演的太烂了,别演了,你来演检票员吧,让旁边小李来演要出行路由的奥巴马吧。奥巴马不情愿的说了一声:“好吧,希望小李能够受的了你”。

“action”,导演又喊了一声,故事开始了~

AuthenticationManager

奥巴马当了检票员以后,特别高兴,因为他有权利了呀,他可以控制别人能不能上车了,说不定还能偷偷放几个人进去捞点外快呢。

得知了他能干什么以后,他觉得检票员这个名字简直太 low 了,很快,他就有了一个新的高大上的名字,叫:认证管理员(AuthenticationManager),而且,他觉得他自己应该处在整个核心位置,为什么呢?你想想看,那么庞大的一套铁路载人系统,能不能有收入有钱赚,全靠他给不给放人进去,如果一个人都不放进去,另外那一大帮人只能去喝西北风了。

到这里,聪明的同学可能已经知道奥巴马把他自己放在怎么样一个核心位置了。对,他把自己放到了 HttpContext 里面。怎么样? 够核心吧。

这里延伸第一个知识点:AuthenticationManager 所处的位置

有同学在上面的截图里面发现了 public abstract ClaimsPrincipal User { get; set; }, 这不就是我们上一篇中讲到的 “ 证件当事人 ” ,现在小李扮演的那个角色么? 对,这个 User 就是本文中的小李,被你提前发现他躲着这里了,嘿嘿。

还有一个知识点,就是 AuthenticationScheme,什么意思呢? 且看
奥巴马敢把自己放在这么核心的位置也是有他的能力的,怎么讲呢? 比如说在检票的时候,别人递过来一张身份证和一张火车票,那怎么样验证这两个证件是合法的呢? 以下就是奥巴马提出的针对两种证件的验证方案:

方案1、针对身份证的验证,可以查看其本人是否和身份证头像是否一致,年龄是否符合当事人具体年龄。
方案2、针对火车票的验证,可以看车次,时间是否符合发车目标,另外可以看车票上的身份号码是否和身份证一致。

其中,这每一种方案,就对应一个 AuthenticationScheme(验证方案名称),是不是明白了。

这就是第二个知识点 AuthenticationScheme 很重要。

知道了奥巴马的职责后,就很容易的把代码写出来了:

public abstract class AuthenticationManager{    //AuthenticateContext包含了需要认证的上下文,里面就有小李public abstract Task AuthenticateAsync(AuthenticateContext context);    //握手public abstract Task ChallengeAsync(string authenticationScheme, AuthenticationProperties properties, ChallengeBehavior behavior);    //登入public abstract Task SignInAsync(string authenticationScheme, ClaimsPrincipal principal, AuthenticationProperties properties);    //登出public abstract Task SignOutAsync(string authenticationScheme, AuthenticationProperties properties);
}

奥巴马做为一个检票员,有一个认证方法,AuthenticateAsync() ,注意这是其一个核心功能,其他几个都可以没有,但是唯独不能没有这个功能,没有的话他就不能称之为一个检票员了。

然后还有一个握手ChallengeAsync,登入SignInAsync和登出SignOutAsync,下面说说笔者对这三个方法的理解吧。

ChallengeAsync:是社区协议文件 RFC2167 定义的关于在HTTP Authentication 过程中的一种关于握手的一个过程,主要是摘要认证(digest authentication),更多信息查看这里。

是不是有点专业,看不懂,没事,有通俗版本的。 小李要进站了,这个时候小李问了一下我们的检票员奥巴马先生。

  • 小李:“你好,检票员,我可以进站吗?”

  • 检票员奥巴马:“要赶火车吗?可以啊,请出示你的证件?”

  • 小李:“好的,这是我的证件,你检查一下?”

  • 检票员奥巴马:“嗯,证件没问题,进去吧”

这样一个过程就是握手(digest-challenge)或者叫问答的一个过程,明白了 ChallengeAsync 的原理了吧? 是不是很简单。

SignInAsyncSignOutAsync:个人觉得这两个不应该放在这里,因为并不属于认证的职责,也不属于协议规定的内容。但是这两个方法确实需要抽象,应该单独抽取一个接口存放,至于为什么这样做,或许是因为以下原因:

1、对登入登出的抽象是和认证紧密结合的,大多数情况下认证资料的保存是需要在SignIn进行的,比如 Cookies Authentication 中间件就在SignIn方法里面做了Cookie的保存。

2、 AuthenticationManager 这个对象是处在 HttpContext
上下文里面的,本着面向抽象和封装的原则,放到其里面是合适的,这样能够很方便的用户对其调用。

关于 AuthenticationManager 已经介绍完了,是不是很简单呢?

IAuthenticationHandler

有些同学可能会问了,如果 AuthenticationManager 不提供接口的话,只是一个抽象类的话,那如果自定义认证方法就必须继承它,这对于开发者来说是不友好的,也违背了面向接口编程的理念。嗯,确实是这样,那么接口来了:

public interface IAuthenticationHandler{    void GetDescriptions(DescribeSchemesContext context);    Task AuthenticateAsync(AuthenticateContext context);    Task ChallengeAsync(ChallengeContext context);    Task SignInAsync(SignInContext context);    Task SignOutAsync(SignOutContext context);
}

这个接口是在 AuthenticationManager 实现类 DefaultAuthenticationManager 中延伸出来的,所以大家不用再去看里面的源码了,记住以后如果需要重写认证相关的东西,实现IAuthenticationHandler就可以了。

Authentication 中间件

对 IAuthenticationHandler 的初步实现,封装了 AuthenticationHandler 这个抽象类,把具体的核心功能都交给下游去实现了,下面的CookieAuthentication 中间件核心类 CookieAuthenticationHandler 就是继承自AuthenticationHandler, 知道这么多就够了。

CookieAuthentication 中间件

故事还要继续,奥巴马在接到小李递来的身份证和火车票之后,首先拿着火车票在一个二维码机器上扫描了一下,然后又拿着身份证在一个机器上刷了一下,经过核查,发现都没有问题。于是拿起印章在上面盖了一个 “ 验讫 ”。

这中间都发生了什么呢?

首先,在二维码扫描的过程,这个过程二维码机器会解析你火车票上的二维码,如果发现解析失败,会直接响应认证失败。也就是你别想进站了。

如果解析成功,就会得到你这个票据中的信息了,然后拿到你票据里面的的当事人信息进行验证是否被列为了铁路局黑名单中。

如果验证通过,则会给你颁发一个识别码,把符合你身份的一个识别码写入到你的火车票中和检票员旁边的电脑系统中,即 “ 验讫 ”。

话说这个验讫有点高级,它会向你的火车票芯片中写入一些信息,那么都写入些什么信息呢? 1、奥巴马个人的信息。2、验证途中的一些上下信息。3、使用的验证方案。

知道了,这些之后,那么就很容易实现这个验证方法了,对吧? 以下是 CookieAuthentication 中间件中的核心类 CookieAuthenticationHandler 的里面的核心方法HandleAuthenticateAsync(),同样你可以理解为实现的 IAuthenticationHandler 接口的 AuthenticateAsync:

protected override async Task<AuthenticateResult> HandleAuthenticateAsync(){    // 解析二维码var result = await EnsureCookieTicket();    if (!result.Succeeded){        return result;}    // 从二维码中拿当事人信息进行验证var context = new CookieValidatePrincipalContext(Context, result.Ticket, Options);    await Options.Events.ValidatePrincipal(context);    if (context.Principal == null){        return AuthenticateResult.Fail("No principal.");}    if (context.ShouldRenew){RequestRefresh(result.Ticket);}    // 验讫, 写入芯片return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme));
}

HandleSignInAsync

我们故事继续……

奥巴马检票完成之后,把票就交给了小李,小李拿到票之后,导演又喊了一声:“ cut ”……

怎么又停了,小李和奥巴马一肚子的疑惑,导演说:“ 奥巴马呀,你检票员演的不错,还是继续扮演你的本职角色吧,演好了中午盒饭给你双份,小李,你来演检票员吧 ”。
可以吃两份盒饭了,奥巴马听后心里还是很开心。

“action” 导演喊了一声……

奥巴马接过票,向着车站里面的列车停车处走去,走到了列车门口要进去的时候,又出现了一个人,奥巴马知道,这个人就是做车内乘客登记的(ps: 一般情况下,做乘客登记都是在列车行驶的过程中,在这里我们假设这个做乘客登记的人比较勤快,就在车门口守着),登记完成之后就让奥巴马进去了。

那么,登记这个过程中都干了些什么呢?

首先,登记员的手持设备会解析火车票票里面写入芯片中的信息,发现没有问题,就开始向自己手里面的登记本登记信息了,主要包含车票主人信息,过期时间,审核人等。

这样整个过程就是 HandleSignInAsync 的一个过程,换成程序术语就是,组装 Cookie 登入上下文信息,写入到 Http 流的 header 中,也就写入到了客户端浏览器cookie。

至此,整个过程就完了,我们来看一下代码:

//方法里面的流程,我只列出了核心部分,影响阅读的全删了protected override async Task HandleSignInAsync(SignInContext signin){    // 解析芯片中的信息var result = await EnsureCookieTicket();    // 组织登入上下文,设置过期时间等// 使用 data protected 加密登记本上的信息var cookieValue = Options.TicketDataFormat.Protect(ticket);    // 写入到浏览器headerawait ApplyHeaders(cookieValue);
}

不想深入了解的可以忽略这部分内容:
在 HandleSignInAsync 这个函数的源码中,其中有一个很巧妙的设计, 就是 await Options.Events.SignedIn(signedInContext); 这样一句代码,干什么用的呢? 而且前后一共调用了两次,有同学知道是为什么吗? 我准备在下一篇中给出答案。

还记得前面 HttpContext 中的ClaimsPrincipal User吗? 就是小李临时顶替的那个角色,现在有值了,他就是是奥巴马了。

奥巴马在座位上坐好之后,经过6个小时的路程就从北京到杭州了,不得不佩服中国高铁的速度呀,在欣赏晚西湖的风景后,奥巴马给我们传来了一张照片:

至此,CookieAuthentication 中间件的整个工作流程已经讲完了,故事也结束了。

以上,就是这两行代码背后的故事:

var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "奥巴马") }, CookieAuthenticationDefaults.AuthenticationScheme));await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);

总结

在本篇中我们知道了 AuthenticationManager,也知道了 IAuthenticationHandler 并且简单的介绍了一下 Authentication 中间件和 CookieAuthentication 中间件,其中 CookieAuthentication 中间件是我们以后使用最多的一个中间件了,本篇也对其做了一个详细的介绍,我想通过本篇文章在以后使用的过程中应该问题不大了。

有同学可能会问了,讲了这么多认证的东西它和 Identity 有什么关系呢? 难道我通篇都在隐藏他和 Identity 的关系你没看出来?。。。。真的想知道? 看下一篇吧。

原文地址:http://www.cnblogs.com/savorboard/p/aspnetcore-identity2.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/327947.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL笔记汇总---狂神说

公众号笔记 1初识MySQL 2数据库操作 3DML语言 4使用DQL查询数据 5MySQL函数 6事务和索引 7权限及如何设计数据库

软件记录

Tampermonkey 加一个脚本可以下载百度文档的文章 不过还是冰点好用 直接下载下来百度文档&#xff0c; 树洞ocr 2.3兆 可以一段一段的进行图片识别 天若OCR开源版V5.0.0 processon 百度搜索 类似于 viso

python快捷方式图标_python – PyInstaller无法更改快捷方式图标

我的问题如下,虽然我可以在可执行文件本身上设置我喜欢的任何图标,但我无法更改此图标我尝试了所有的东西,但是当我选择exe文件或者当我创建一个快捷方式时,这个PyInstaller图标就会出现&#xff01;这是exe看起来的样子这是棘手的部分,如果我设置选项–onefile,这不会发生.如果…

Typora的使用技巧

不能更好的对齐&#xff0c;按enter键不能删除前缀 Ctrl加/&#xff1a;查看源代码 删除多余的-即可 嘿嘿

Java中几种常量池的区分

转载自 Java中几种常量池的区分在java的内存分配中&#xff0c;经常听到很多关于常量池的描述&#xff0c;我开始看的时候也是看的很模糊&#xff0c;网上五花八门的说法简直太多了&#xff0c;最后查阅各种资料&#xff0c;终于算是差不多理清了&#xff0c;很多网上说法都有…

perform指标分析_performace 监控统计

浏览器浏览器是多进程的&#xff0c;js是单线程的。进程&#xff1a;程序运行&#xff0c;资源分配。线程&#xff1a;进程中独立执行的流浏览器有哪些进程Browser进程&#xff1a; 浏览器的主进程(负责协调、主控)GPU进程&#xff1a; 最多一个&#xff0c;用于3D绘制等浏览器…

hibernate正向生成数据库表以及配置——Teacher.hbm.xml

<?xml version"1.0" encoding"utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Mapping file au…

数据库中modify和change的区别

修改字段 : ALTER TABLE 表名 MODIFY 字段名 列类型[属性] 无法重命名ALTER TABLE 表名 CHANGE 旧字段名 新字段名 列属性[属性] 可以重命名

ExceptionLess新玩法 — 记日志

ExceptionLess 之前也有介绍过这个框架&#xff0c;其实网上也有很多的资料&#xff0c;无论是部署还是一些详细的高级玩法都讲的很清楚也很棒&#xff0c;博主也学习了一些他们的博文&#xff0c;因为很多的东西比如本地部署别人已经写了&#xff0c;我再去写也不免俗套。所以…

19年8月 字母哥 番外篇:周边技术生态

番外篇&#xff1a;周边技术生态 如何使用git查看本教程代码 centos7安装docker图文详解 docker安装mongodb(单点)图文详解 如何使用mybatis自动生成的代码

pt939g联通_尝试修改友华PT939G的省份设置,成功!

本帖最后由 笑西风 于 2020-7-4 08:04 编辑个人感觉友华PT939G无线光猫一体机的配置还不错&#xff0c;核心跟新路由三相同&#xff0c;所以总想折腾它。之前找了各类root/1234&#xff0c;user/1234之类的密码&#xff0c;最终通过CSDN大侠的yhtcAdmin /Cm1YHfw登录了光猫。准…

MySQL中有外键时数据表的删除方法

直接删除grade&#xff0c;被引用的数据表时如下 报错 解决方法 先删除student&#xff0c;要引用的数据表 然后删除grade&#xff0c;被引用的数据表 成功

微软全球副总裁给你发了一张Connect 2016专属邀请卡:信仰再充值!Connect 2016技术大会在线直播!

Connect(); 2016在线直播啦&#xff01;11月16日晚 22:45不见不散&#xff01;快来制作专属自己的大会邀请函&#xff01; Connect(); 是微软面向开发者的一场顶级线上技术盛会&#xff0c;意在为广大开发者带来微软最新的开发技术资讯&#xff0c;每年有超过50万资深开发人员及…

MongoDb安装使用

Microsoft Windows [版本 10.0.17763.107] (c) 2018 Microsoft Corporation。保留所有权利。 C:\Users\Administrator>mongon mongon 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 C:\Users\Administrator>mongo mongo 不是内部或外部命令&#x…

Java中的String与常量池

转载自 Java中的String与常量池string是java中的字符串。String类是不可变的,对String类的任何改变,都是返回一个新的String类对象。下面介绍java中的String与常量池。 1. 首先String不属于8种基本数据类型&#xff0c;String是一个对象。 因为对象的默认值是null&#xff0c;…

tp中怎么执行mysql事务_tp中使用事务

是什么事务是为了防止&#xff0c;多个操作&#xff0c;其中有失败&#xff0c;数据有部分被执行成功的时候使用的。比如&#xff0c;银行&#xff0c;用户转账。张三钱扣了&#xff0c;结果李四钱还增加&#xff01;这个时候需要使用事务&#xff0c;确保张三钱扣了&#xff0…

TRUNCATE vs DELETE命令

TRUNCATE vs DELETE命令 作用&#xff1a;用于完全清空表数据 , 但表结构 , 索引 , 约束等不变 ; 语法&#xff1a; TRUNCATE [TABLE] table_name;-- 清空年级表 TRUNCATE grade注意&#xff1a;区别于DELETE命令 相同 : 都能删除数据 , 不删除表结构 , 但TRUNCATE速度更快 …

mysql 时间 1_(转)mysql日期时间函数1

MySQL 日期跟时间函数(一)作者&#xff1a; Mr.ZhangMySQL 日期跟时间的样式在MySQL 中有很多有用处的日期跟时间函数。我们常常看到许多应用于日期的计算是在代码方面上进行的&#xff0c;但是其实他们完全可以使用MySQL中自带的函数来实现。在我们实际的查看MySQL的时间跟日期…

ASP.NET Core 整合Autofac和Castle实现自动AOP拦截

前言&#xff1a; 除了ASP.NETCore自带的IOC容器外&#xff0c;我们还可以使用其他成熟的DI框架&#xff0c;如Autofac&#xff0c;StructureMap等&#xff08;笔者只用过Unity&#xff0c;Ninject和Castle&#xff09;。 1.ASP.NET Core中的Autofac 首先在Project.json的Depen…