前言

在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列()奠定一下基础。

有关于 Authentication 的知识太广,所以本篇介绍几个在 ASP.NET Core 认证中会使用到的中间件,还有Authentication的一些零碎知识点,这些知识点对于 ASP.NET 认证体系的理解至关重要。

在 Github 中 ASP.NET Core 关于 Authentication 的实现有以下几个包,那么这几个包的功能分别是干什么用的呢?我们一一看一下。

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,HandleSignOutAsyncHandleForbiddenAsync,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 方法。

大致步骤如下:

  1. 读取 Http Request Header 中的 Authorization 信息
  2. 读取 Authorization 值里面的 Bearer 信息
  3. 验证 Bearer 是否合法,会得到一个 ClaimsPrincipal
  4. 使用 ClaimsPrincipal 构建一个 Ticket(票据)
  5. 调用 Options.Events.TokenValidated(context),用户可以重写此方法验证Token合法性
  6. 返回验证成功

其他的知识点

这几个中间件对会有对应的 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 中的那些认证中间件及一些重要知识点的更多相关文章

  1. [转]ASP.NET Core 中的那些认证中间件及一些重要知识点

    本文转自:http://www.qingruanit.net/c_all/article_6645.html 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系 ...

  2. 如何简单的在 ASP.NET Core 中集成 JWT 认证?

    前情提要:ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统 文章超长预警(1万字以上),不想看全部实现过程的同学可以直接跳转到末尾查看成果或者一键安装相关的 nuget 包 自上一 ...

  3. ASP.NET Core 中jwt授权认证的流程原理

    目录 1,快速实现授权验证 1.1 添加 JWT 服务配置 1.2 颁发 Token 1.3 添加 API访问 2,探究授权认证中间件 2.1 实现 Token 解析 2.2 实现校验认证 1,快速实 ...

  4. 在ASP.NET Core中编写合格的中间件

    这篇文章探讨了让不同的请求去使用不同的中间件,那么我们应该如何配置ASP.NET Core中间件?其实中间件只是在ASP.NET Core中处理Web请求的管道.所有ASP.NET Core应用程序至 ...

  5. 在asp.net core中使用cookie认证

    以admin控制器为要认证的控制器举例 1.对控制器设置权限特性 //a 认证命名空间 using Microsoft.AspNetCore.Authorization; using Microsof ...

  6. ASP.NET Core 中基于工厂的中间件激活

    IMiddlewareFactory/IMiddleware 是中间件激活的扩展点. UseMiddleware 扩展方法检查中间件的已注册类型是否实现 IMiddleware. 如果是,则使用在容器 ...

  7. ASP.NET CORE中使用Cookie身份认证

    大家在使用ASP.NET的时候一定都用过FormsAuthentication做登录用户的身份认证,FormsAuthentication的核心就是Cookie,ASP.NET会将用户名存储在Cook ...

  8. [译]在Asp.Net Core 中使用外部登陆(google、微博...)

    原文出自Rui Figueiredo的博文<External Login Providers in ASP.NET Core> 摘要:本文主要介绍了使用外部登陆提供程序登陆的流程,以及身份 ...

  9. asp.net core 2.0的认证和授权

    在asp.net core中,微软提供了基于认证(Authentication)和授权(Authorization)的方式,来实现权限管理的,本篇博文,介绍基于固定角色的权限管理和自定义角色权限管理, ...

随机推荐

  1. 如何一步一步用DDD设计一个电商网站(四)—— 把商品卖给用户

    阅读目录 前言 怎么卖 领域服务的使用 回到现实 结语 一.前言 上篇中我们讲述了“把商品卖给用户”中的商品和用户的初步设计.现在把剩余的“卖”这个动作给做了.这里提醒一下,正常情况下,我们的每一步业 ...

  2. 探究@property申明对象属性时copy与strong的区别

    一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...

  3. Zabbix基本配置及监控主机

    监控主机一版需要在被监控的主机上安装Zabbix Agent 监控主机 安装zabbix-agent 首先需要在被监控的主机上安装agent,可以下载预编译好的RPM进行安装,下载地址:http:// ...

  4. .NET平台开源项目速览(17)FluentConsole让你的控制台酷起来

    从该系列的第一篇文章 .NET平台开源项目速览(1)SharpConfig配置文件读写组件 开始,不知不觉已经到第17篇了.每一次我们都是介绍一个小巧甚至微不足道的.NET平台的开源软件,或者学习,或 ...

  5. Android权限管理之Android 6.0运行时权限及解决办法

    前言: 今天还是围绕着最近面试的一个热门话题Android 6.0权限适配来总结学习,其实Android 6.0权限适配我们公司是在今年5月份才开始做,算是比较晚的吧,不过现在Android 6.0以 ...

  6. 【原创分享·微信支付】C# MVC 微信支付之微信模板消息推送

    微信支付之微信模板消息推送                    今天我要跟大家分享的是“模板消息”的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信生存的呀,所以他能不 ...

  7. C#中Length和Count的区别(个人观点)

    这篇文章将会很短...短到比你的JJ还短,当然开玩笑了.网上有说过Length和count的区别,都是很含糊的,我没有发现有 文章说得比较透彻的,所以,虽然这篇文章很短,我还是希望能留在首页,听听大家 ...

  8. IL异常处理

    异常处理在程序中也算是比较重要的一部分了,IL异常处理在C#里面实现会用到一些新的方法 1.BeginExceptionBlock:异常块代码开始,相当于try,但是感觉又不太像 2.EndExcep ...

  9. 【夯实PHP基础】PHP常用类和函数总结

    本文地址 代码提纲: 1. 字符串处理类及函数 2. 数组处理类及函数 3 .web处理类及函数 将常用的PHP的类和函数总结到这里,主要是 自己用过的,比较有感觉. 1. [字符串处理] 1)[ut ...

  10. BPM配置故事之案例5-必填与水印文本

    物资申请表改好了,但是没过两天老李又找来了. 老李:这个表格每次都是各个部门发给我们,再由我们采购部来填,太影响效率了,以后要让他们自己填. 小明:那就让他们填呗,他们有权限啊. 老李:可是他们说不会 ...