前言
在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础。
有关于 Authentication 的知识太广,所以本篇介绍几个在 ASP.NET Core 认证中会使用到的中间件,还有Authentication的一些零碎知识点,这些知识点对于 ASP.NET 认证体系的理解至关重要。
在 Github 中 ASP.NET Core 关于 Authentication 的实现有以下几个包,那么这几个包的功能分别是干什么用的呢?我们一一看一下。
- Microsoft.AspNetCore.Authentication
- Microsoft.AspNetCore.Authentication.Cookies
- Microsoft.AspNetCore.Authentication.OAuth
- Microsoft.AspNetCore.Authentication.OpenIdConnect
- Microsoft.AspNetCore.Authentication.JwtBearer
Microsoft.AspNetCore.Authentication
Authentication 在 ASP.NET Core 中,对于 Authentication(认证) 的抽象实现,此中间件用来处理或者提供管道中的 HttpContext 里面的 AuthenticationManager 相关功能抽象实现。
HttpContext 中的 User 相关信息同样在此中间件中被初始化。
对于开发人员只需要了解此中间件中的这几个对象即可:
-
AuthenticationOptions
对象主要是用来提供认证相关中间件配置项,后面的 OpenIdConnect,OAuth,Cookie 等均是继承于此。 -
AuthenticationHandler
对请求流程中(Pre-Request)中相关认证部分提供的一个抽象处理类,同样后面的其他几个中间件均是继承于此。
在 AuthenticationHandler
中, 有几个比较重要的方法:
-
HandleAuthenticateAsync
:处理认证流程中的一个核心方法,这个方法返回AuthenticateResult
来标记是否认证成功以及返回认证过后的票据(AuthenticationTicket)。 -
HandleUnauthorizedAsync
:可以重写此方法用来处理相应401未授权等问题,修改头,或者跳转等。 -
HandleSignInAsync
:对齐 HttpContext AuthenticationManager 中的 SignInAsync -
HandleSignOutAsync
:对齐 HttpContext AuthenticationManager 中的 SignOutAsync -
HandleForbiddenAsync
:对齐 HttpContext AuthenticationManager 中的 ForbidAsync,用来处理禁用等结果
以上关于 AuthenticationHandler 我列出来的这些方法都是非常容易理解的,我们在继承Authentication实现我们自己的一个中间件的时候只需要重写上面的一个或者多个方法即可。
还有一个 RemoteAuthenticationHandler
它也是继承AuthenticationHandler,主要是针对于远程调用提供出来的一个抽象,什么意思呢?因为很多时候我们的认证是基于OAuth的,也就是说用户的状态信息是存储到Http Header 里面每次进行往来的,而不是cookie等,所以在这个类里面了一个HandleRemoteAuthenticateAsync
的函数。
Microsoft.AspNetCore.Authentication.Cookies
Cookies 认证是 ASP.NET Core Identity 默认使用的身份认证方式,那么这个中间件主要是干什么的呢
我们知道,在 ASP.NET Core 中已经没有了 Forms 认证,取而代之的是一个叫 “个人用户账户” 的一个东西,如下图,你在新建一个ASP.ENT Core Web 应用程序的时候就会发现它,它实际上就是 Identity。那么Forms认证去哪里了呢?对,就是换了个名字叫 Identity。
在此中间件中,主要是针对于Forms认证的一个实现,也就是说它通过Cookie把用户的个人身份信息通过加密的票据存储的Cookie中去,如果看过我之前Identity系列文章的话,那么应该知道用户的个人身份信息就是 ClaimsIdentity 相关的东西。
这个中间件引用了Authentication,CookieAuthenticationHandler 类继承了 AuthenticationHandler 并重写了 HandleAuthenticateAsync
,HandleSignInAsync
,HandleSignOutAsync
,HandleForbiddenAsync
,HandleUnauthorizedAsync
等方法,就是上一节中列出来的几个方法。
我们主要看一下核心方法 HandleAuthenticateAsync
在 Cookie 中间件怎么实现的:
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
//读取并解密从浏览器获取的Cookie
var result = await EnsureCookieTicket();
if (!result.Succeeded)
{
return result;
}
// 使用上一步结果构造 CookieValidatePrincipalContext 对象
// 这个对象是一个包装类,里面装着 ClaimsPrincipal、AuthenticationProperties
var context = new CookieValidatePrincipalContext(Context, result.Ticket, Options);
// 默认是空的实现,可以重写来验证 CookieValidatePrincipalContext 是否有异常
await Options.Events.ValidatePrincipal(context);
if (context.Principal == null)
{
return AuthenticateResult.Fail("No principal.");
}
// 表示是否需要刷新Cookie
if (context.ShouldRenew)
{
RequestRefresh(result.Ticket);
}
return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme));
}
总结一下就是解密Http请求中的Cookie信息,然后验证Cookie是否合法,然后提取Cookie中的信息返回结果。
还有一个方法就是 HandleSignInAsync
,根据名字可以看出主要是处理登入相关操作的,在这个方法里面主要是根据Claims信息生成加入过后的票据,同时会向票据中写入过期时间,是否持久化等信息。 是否持久化的意思就是用户在登陆界面是否勾选了 “记住我” 这个操作。
Microsoft.AspNetCore.Authentication.OAuth
OAuth 是针对于 OAuth 2.0 标准实现的一个客户端程序,记住是客户端,它不具备发放Token或者 Client_id ,Code 等的功能,它的作用是帮你简化对OAuth2.0服务端程序的调用。 它对应 OAuth 2.0 标准中的 “获取Access_Token” 这一步骤,如果对腾讯开放平台QQ授权比较了解的话,就是对应 “使用Authorization_Code获取Access_Token” 这一步骤。
点击 这里 查看图片详情。
OAuth 实现的具体细节就不一一介绍了。
Microsoft.AspNetCore.Authentication.OpenIdConnect
获取 OpenId 是OAuth 授权中的一个步骤,OpenId 它是具体的一个Token Key,不要把他理解成一种授权方式或者和OAuth不同的另外一种东西,他们是一体的。
代码上就不详细说了,和上面的都差不多。主要说一下它们之间的区别或者叫联系。
OAuth 它主要是针对于授权(Authorization),而OpenID主要是针对于认证(Authentication),他们之间是互补的。
那什么叫授权呢? 比如小明是使用我们网站的一个用户,他现在要在另外一个网站使用在我们网站注册的账号,那授权就是代表小明在另外一个网站能够做什么东西? 比如能够查看资料,头像,相册等等,授权会给用户发放一个叫 Access_Token 的东西。
而认证关注的这个用户是谁,它是用来证明用户东西。比如小明要访问它的相册,那我们网站就需要小明提供一个叫OpenId的一个东西,我们只认这个OpenId。那小明从哪里得到它的这个OpenId呢,对,就是使用上一步的Access_Token 来换取这 个 OpenId ,以后访问的时候不认 Access_Token ,只认识OpenId这个东西。
一般情况下,OpenId 是需要客户端进行持久化的,那么对应在 ASP.NET Core Identity 中,就是存储在 UsersLogin 表里面的 ProviderKey 字段,懂了吧,懂了给个推荐呗
Microsoft.AspNetCore.Authentication.JwtBearer
JwtBearer 这个中间件是依赖于上一步的 OpenIdConnect 中间件的,看到了吧,其实这几个中间件是环环嵌套的。
可能很多同学听说过 Jwt,但是大多数人都有一个误区,认为JWT是一种认证方式,经常在QQ群里面听过 前面一个同学在问 实际开发中前后端分离的时候安全怎么做的?,下面一个人回答使用JWT。
其实JWT 它不是一种认证方式,也不是一种认证的技术,它是一个规范,一个标准。
Jwt(Json Web Token)的官网是 https://jwt.io,下面是对JWT的一个说明
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
JSON Web Tokens(JWT) 是一个开放的行业标准( RFC 7519),用于在双方之间传递安全的Claims。
JWT 在身份认证中的应用场景:
在身份认证场景下,一旦用户完成了登陆,在接下来的每个请求中包含JWT,可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。由于它的开销非常小,可以轻松的在不同域名的系统中传递,所有目前在单点登录(SSO)中比较广泛的使用了该技术。
好了,不过多的说了。 我们还是接着看一下 JwtBearer 中间件,同样它重写了 HandleAuthenticateAsync
方法。
大致步骤如下:
- 读取 Http Request Header 中的 Authorization 信息
- 读取 Authorization 值里面的 Bearer 信息
- 验证 Bearer 是否合法,会得到一个 ClaimsPrincipal
- 使用 ClaimsPrincipal 构建一个 Ticket(票据)
- 调用 Options.Events.TokenValidated(context),用户可以重写此方法验证Token合法性
- 返回验证成功
其他的知识点
这几个中间件对会有对应的 Options 配置项,在这些配置项中,都会有 AuthenticationScheme
, AutomaticAuthenticate
, AutomaticChallenge
这几个属性,那这几个东西都是干嘛的呢?
AuthenticationScheme
我在 《ASP.NET Core 之 Identity 入门(二)》 一文中提到过这个知识点,当时说很重要,这里可以看到了吧,每一种验证中间件都会使用到这个东西,我比较偏向于把这个翻译成 “认证方案”。
我们知道,在 MVC 程序中一般通过在 Controller 或者 Action 上 打标记(Attribute)的方式进行授权,最典型的就是新建一个项目的时候里面的AccountController。
[Authorize]
public class AccountController : Controller
{
}
在 Authorize 这个 Attribute 中,有一个属性叫做 ActiveAuthenticationSchemes 的东西,那么这个东西是干什么用的呢?
ActiveAuthenticationSchemes 就是对应着中间件Options里面配置的 AuthenticationScheme ,如果你不指定的话,在使用多个身份验证组件的时候会有问题,会有什么问题呢?往下看
AutomaticAuthenticate
AutomaticAuthenticate 很简单,是一个bool类型的字段,用来配置是否处理 AuthenticationHandler 是否处理请求。或者你可以理解为中间件是不是自动的处理认证相关的业务。
AutomaticChallenge
这个重要哦! 当我们使用多个身份验证中间件的时候,那么就要用到这个配置项了,该配置项是用来设置哪个中间件会是身份验证流程中的默认中间件,当代码运行到 Controller 或者 Action 上的 [Authorize]
这个标记的时候,就会触发身份验证流程。默认情况下MVC的Filter会自动的触发[Authorize]
,当然也有一种手动触发Authorize的办法就是使用HttpContext.Authentication.ChallengeAsync()
。
实际上,在验证中间件的管道流程中,应该只有一个组件被设定为 AutomaticChallenge = true
,但其实大多数的中间件这个参数默认都是 true ,这些中间件包括(Identity, Cookie, OAuth, OpenId, IISIntegration, WebListener)等, 这就导致了在整个验证流程中会触发多个中间件对其进行相应,这种冲突大部分不是用户期望的结果。
不幸的是,目前框架对于这种情况并没有一个健壮的机制,如果开发人员对于这种机制不是很清楚的话,可能会造成很大的困扰。
幸运的是,ASP.NET Core 团队已经意识到了这个问题,他们将在 NET Standard 2.0 中对此重新进行设计,比如手动触发的时候应该怎么处理,有多个的时候怎么处理,以及会添加一些语法糖。
目前情况下,当有多个验证中间件的时候,应该怎么处理呢?比如同时使用 Identity 和 JwtBearer。正确的做法是应该禁用掉除 Identity 以外的其他中间件的 AutomaticChallenge,然后指定调用的AuthenticationScheme。也就是说在Controller或者Action显式指定 [Authorize(ActiveAuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
,或者是可以指定一个策略来简化授权调用 [Authorize("ApiPolicy")]
services.AddAuthorization(options =>
{
options.AddPolicy("ApiPolicy", policy =>
{
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
policy.RequireAuthenticatedUser();
});
});
而默认不带参数的 [Authorize]
可以指定AuthorizationPolicie:
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder("Identity.Application").RequireAuthenticatedUser().Build();
});
注意,手动调用 HttpContext.Authentication.ChallengeAsync()
不受 AuthorizationPolicie 影响。
总结
本篇介绍了 ASP.NET Core 有关 Authentication 的几个中间件,然后还有几个比较重要的知识点,这篇文章内容有点多,对于一些人来说可能需要一点时间消化。
最后,如果你觉得这篇文章对你有帮助的话,谢谢你的【推荐】。
如果你对 .NET Core 感兴趣可以关注我,我会定期在博客分享关于 .NET Core 的学习心得。
本文地址:http://www.cnblogs.com/savorboard/p/aspnetcore-authentication.html
作者博客:Savorboard
欢迎转载,请在明显位置给出出处及链接
ASP.NET Core 中的那些认证中间件及一些重要知识点的更多相关文章
-
[转]ASP.NET Core 中的那些认证中间件及一些重要知识点
本文转自:http://www.qingruanit.net/c_all/article_6645.html 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系 ...
-
如何简单的在 ASP.NET Core 中集成 JWT 认证?
前情提要:ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统 文章超长预警(1万字以上),不想看全部实现过程的同学可以直接跳转到末尾查看成果或者一键安装相关的 nuget 包 自上一 ...
-
ASP.NET Core 中jwt授权认证的流程原理
目录 1,快速实现授权验证 1.1 添加 JWT 服务配置 1.2 颁发 Token 1.3 添加 API访问 2,探究授权认证中间件 2.1 实现 Token 解析 2.2 实现校验认证 1,快速实 ...
-
在ASP.NET Core中编写合格的中间件
这篇文章探讨了让不同的请求去使用不同的中间件,那么我们应该如何配置ASP.NET Core中间件?其实中间件只是在ASP.NET Core中处理Web请求的管道.所有ASP.NET Core应用程序至 ...
-
在asp.net core中使用cookie认证
以admin控制器为要认证的控制器举例 1.对控制器设置权限特性 //a 认证命名空间 using Microsoft.AspNetCore.Authorization; using Microsof ...
-
ASP.NET Core 中基于工厂的中间件激活
IMiddlewareFactory/IMiddleware 是中间件激活的扩展点. UseMiddleware 扩展方法检查中间件的已注册类型是否实现 IMiddleware. 如果是,则使用在容器 ...
-
ASP.NET CORE中使用Cookie身份认证
大家在使用ASP.NET的时候一定都用过FormsAuthentication做登录用户的身份认证,FormsAuthentication的核心就是Cookie,ASP.NET会将用户名存储在Cook ...
-
[译]在Asp.Net Core 中使用外部登陆(google、微博...)
原文出自Rui Figueiredo的博文<External Login Providers in ASP.NET Core> 摘要:本文主要介绍了使用外部登陆提供程序登陆的流程,以及身份 ...
-
asp.net core 2.0的认证和授权
在asp.net core中,微软提供了基于认证(Authentication)和授权(Authorization)的方式,来实现权限管理的,本篇博文,介绍基于固定角色的权限管理和自定义角色权限管理, ...
随机推荐
-
分享一个基于HTML5实现的视频播放器
什么是hivideo? 最近一段时间在使用PhoneGap开发一个App应用,App需要播放视频,本想直接使用html5的video,但使用它在全屏播放时不支持横屏播放,只能放弃.最终决定还是自己封装 ...
-
mysql添加索引命令
创建脚本 1.PRIMARY KEY(主键索引)mysql>ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) 2.UNI ...
-
Nutch主要类代码分析之一(Injector)
Injector(org.apache.nutch.crawl.Injector): 输入:种子列表文件所在的目录 输出:crawldb(保存URL以及其相应信息的数据库) 作用:把种子URL注入到c ...
-
Makefile中的特殊宏定义以及实用选项
Makefile中的一些特殊宏定义的名字跟shell中的位置变量挺相似的. $? 当前目标所依赖的文件列表中比当前目标文件还要新的文件 $@ 当前目标我名字 $< 当前依赖文件的名 ...
-
UI进阶 CocoaPods的安装使用步骤
一. CocoaPods简介 CocoaPods是一个用来帮助我们管理第三方依赖库的工具.在开发iOS应用时,会经常使用第三方类库,比如SDWebImage.AFNetworking等等,手动的下载与 ...
-
$http post 取不到数据
默认情况下,jQuery传输数据使用Content-Type: x-www-form-urlencoded 和类似于"foo=bar&baz=moe"的序列,然而Angul ...
-
Go - Struct
定义 go 语言中的struct与c的很相似,此外,go没有Class,也没有继承. stuct的格式为:type <name> struct{} package main import ...
-
【Android Developers Training】 102. 序言:让你的应用获知地点
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
-
Android为TV端助力之WebView开发踩坑一
在Android清单配置文件里面 自定义application时,在4.4系统上面不能加上一个属性,见下图 否则界面将不会显示任何数据,在更高或者更低的系统上面没有测试!
-
[Swift]LeetCode965. 单值二叉树 | Univalued Binary Tree
A binary tree is univalued if every node in the tree has the same value. Return true if and only if ...