ASP.NET Core 中的那些认证中间件及一些重要知识点
前言
在讀這篇文章之間,建議先看一下我的 ASP.NET Core 之 Identity 入門系列(ASP.NET Core 之 Identity 入門(一),ASP.NET Core 之 Identity 入門(二),ASP.NET Core 之 Identity 入門(三)奠定一下基礎(chǔ)。
有關(guān)于 Authentication 的知識太廣,所以本篇介紹幾個在 ASP.NET Core 認(rèn)證中會使用到的中間件,還有Authentication的一些零碎知識點,這些知識點對于 ASP.NET 認(rèn)證體系的理解至關(guān)重要。
在 Github 中 ASP.NET Core 關(guān)于 Authentication 的實現(xiàn)有以下幾個包,那么這幾個包的功能分別是干什么用的呢?我們一一看一下。
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(認(rèn)證) 的抽象實現(xiàn),此中間件用來處理或者提供管道中的 HttpContext 里面的 AuthenticationManager 相關(guān)功能抽象實現(xiàn)。
HttpContext 中的 User 相關(guān)信息同樣在此中間件中被初始化。
對于開發(fā)人員只需要了解此中間件中的這幾個對象即可:
AuthenticationOptions?對象主要是用來提供認(rèn)證相關(guān)中間件配置項,后面的 OpenIdConnect,OAuth,Cookie 等均是繼承于此。
AuthenticationHandler?對請求流程中(Pre-Request)中相關(guān)認(rèn)證部分提供的一個抽象處理類,同樣后面的其他幾個中間件均是繼承于此。
在?AuthenticationHandler?中, 有幾個比較重要的方法:
HandleAuthenticateAsync?:處理認(rèn)證流程中的一個核心方法,這個方法返回?AuthenticateResult來標(biāo)記是否認(rèn)證成功以及返回認(rèn)證過后的票據(jù)(AuthenticationTicket)。
HandleUnauthorizedAsync:可以重寫此方法用來處理相應(yīng)401未授權(quán)等問題,修改頭,或者跳轉(zhuǎn)等。
HandleSignInAsync:對齊 HttpContext AuthenticationManager 中的 SignInAsync
HandleSignOutAsync:對齊 HttpContext AuthenticationManager 中的 SignOutAsync
HandleForbiddenAsync:對齊 HttpContext AuthenticationManager 中的 ForbidAsync,用來處理禁用等結(jié)果
以上關(guān)于 AuthenticationHandler 我列出來的這些方法都是非常容易理解的,我們在繼承Authentication實現(xiàn)我們自己的一個中間件的時候只需要重寫上面的一個或者多個方法即可。
還有一個?RemoteAuthenticationHandler?它也是繼承AuthenticationHandler,主要是針對于遠(yuǎn)程調(diào)用提供出來的一個抽象,什么意思呢?因為很多時候我們的認(rèn)證是基于OAuth的,也就是說用戶的狀態(tài)信息是存儲到Http Header 里面每次進(jìn)行往來的,而不是cookie等,所以在這個類里面了一個HandleRemoteAuthenticateAsync的函數(shù)。
Microsoft.AspNetCore.Authentication.Cookies
Cookies 認(rèn)證是 ASP.NET Core Identity 默認(rèn)使用的身份認(rèn)證方式,那么這個中間件主要是干什么的呢
我們知道,在 ASP.NET Core 中已經(jīng)沒有了 Forms 認(rèn)證,取而代之的是一個叫 “個人用戶賬戶” 的一個東西,如下圖,你在新建一個ASP.ENT Core Web 應(yīng)用程序的時候就會發(fā)現(xiàn)它,它實際上就是 Identity。那么Forms認(rèn)證去哪里了呢?對,就是換了個名字叫 Identity。
在此中間件中,主要是針對于Forms認(rèn)證的一個實現(xiàn),也就是說它通過Cookie把用戶的個人身份信息通過加密的票據(jù)存儲的Cookie中去,如果看過我之前Identity系列文章的話,那么應(yīng)該知道用戶的個人身份信息就是 ClaimsIdentity 相關(guān)的東西。
這個中間件引用了Authentication,CookieAuthenticationHandler 類繼承了 AuthenticationHandler 并重寫了?HandleAuthenticateAsync,HandleSignInAsync,HandleSignOutAsync,HandleForbiddenAsync,HandleUnauthorizedAsync?等方法,就是上一節(jié)中列出來的幾個方法。
我們主要看一下核心方法?HandleAuthenticateAsync?在 Cookie 中間件怎么實現(xiàn)的:
protected override async Task<AuthenticateResult> HandleAuthenticateAsync(){ ? ?//讀取并解密從瀏覽器獲取的Cookievar result = await EnsureCookieTicket(); ? ?if (!result.Succeeded){ ? ? ? ?return result;} ? ? // 使用上一步結(jié)果構(gòu)造 CookieValidatePrincipalContext 對象// 這個對象是一個包裝類,里面裝著 ClaimsPrincipal、AuthenticationPropertiesvar context = new CookieValidatePrincipalContext(Context, result.Ticket, Options); ? ?// 默認(rèn)是空的實現(xiàn),可以重寫來驗證 CookieValidatePrincipalContext 是否有異常await Options.Events.ValidatePrincipal(context); ? ?if (context.Principal == null){ ? ? ? ?return AuthenticateResult.Fail("No principal.");} ? ?// 表示是否需要刷新Cookieif (context.ShouldRenew){RequestRefresh(result.Ticket);} ? ?return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme)); }總結(jié)一下就是解密Http請求中的Cookie信息,然后驗證Cookie是否合法,然后提取Cookie中的信息返回結(jié)果。
還有一個方法就是?HandleSignInAsync?,根據(jù)名字可以看出主要是處理登入相關(guān)操作的,在這個方法里面主要是根據(jù)Claims信息生成加入過后的票據(jù),同時會向票據(jù)中寫入過期時間,是否持久化等信息。 是否持久化的意思就是用戶在登陸界面是否勾選了 “記住我” 這個操作。
Microsoft.AspNetCore.Authentication.OAuth
OAuth 是針對于 OAuth 2.0 標(biāo)準(zhǔn)實現(xiàn)的一個客戶端程序,記住是客戶端,它不具備發(fā)放Token或者 Client_id ,Code 等的功能,它的作用是幫你簡化對OAuth2.0服務(wù)端程序的調(diào)用。 它對應(yīng) OAuth 2.0 標(biāo)準(zhǔn)中的 “獲取Access_Token” 這一步驟,如果對騰訊開放平臺QQ授權(quán)比較了解的話,就是對應(yīng) “使用Authorization_Code獲取Access_Token” 這一步驟。
點擊?這里?查看圖片詳情。
OAuth 實現(xiàn)的具體細(xì)節(jié)就不一一介紹了。
Microsoft.AspNetCore.Authentication.OpenIdConnect
獲取 OpenId 是OAuth 授權(quán)中的一個步驟,OpenId 它是具體的一個Token Key,不要把他理解成一種授權(quán)方式或者和OAuth不同的另外一種東西,他們是一體的。
代碼上就不詳細(xì)說了,和上面的都差不多。主要說一下它們之間的區(qū)別或者叫聯(lián)系。
OAuth 它主要是針對于授權(quán)(Authorization),而OpenID主要是針對于認(rèn)證(Authentication),他們之間是互補(bǔ)的。
那什么叫授權(quán)呢? 比如小明是使用我們網(wǎng)站的一個用戶,他現(xiàn)在要在另外一個網(wǎng)站使用在我們網(wǎng)站注冊的賬號,那授權(quán)就是代表小明在另外一個網(wǎng)站能夠做什么東西? 比如能夠查看資料,頭像,相冊等等,授權(quán)會給用戶發(fā)放一個叫 Access_Token 的東西。
而認(rèn)證關(guān)注的這個用戶是誰,它是用來證明用戶東西。比如小明要訪問它的相冊,那我們網(wǎng)站就需要小明提供一個叫OpenId的一個東西,我們只認(rèn)這個OpenId。那小明從哪里得到它的這個OpenId呢,對,就是使用上一步的Access_Token 來換取這 個 OpenId ,以后訪問的時候不認(rèn) Access_Token ,只認(rèn)識OpenId這個東西。
一般情況下,OpenId 是需要客戶端進(jìn)行持久化的,那么對應(yīng)在 ASP.NET Core Identity 中,就是存儲在 UsersLogin 表里面的 ProviderKey 字段,懂了吧,懂了給個推薦唄
Microsoft.AspNetCore.Authentication.JwtBearer
JwtBearer 這個中間件是依賴于上一步的 OpenIdConnect 中間件的,看到了吧,其實這幾個中間件是環(huán)環(huán)嵌套的。
可能很多同學(xué)聽說過 Jwt,但是大多數(shù)人都有一個誤區(qū),認(rèn)為JWT是一種認(rèn)證方式,經(jīng)常在QQ群里面聽過 前面一個同學(xué)在問 實際開發(fā)中前后端分離的時候安全怎么做的?,下面一個人回答使用JWT。
其實JWT 它不是一種認(rèn)證方式,也不是一種認(rèn)證的技術(shù),它是一個規(guī)范,一個標(biāo)準(zhǔn)。
Jwt(Json Web Token)的官網(wǎng)是?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) 是一個開放的行業(yè)標(biāo)準(zhǔn)( RFC 7519),用于在雙方之間傳遞安全的Claims。
JWT 在身份認(rèn)證中的應(yīng)用場景:
在身份認(rèn)證場景下,一旦用戶完成了登陸,在接下來的每個請求中包含JWT,可以用來驗證用戶身份以及對路由,服務(wù)和資源的訪問權(quán)限進(jìn)行驗證。由于它的開銷非常小,可以輕松的在不同域名的系統(tǒng)中傳遞,所有目前在單點登錄(SSO)中比較廣泛的使用了該技術(shù)。
好了,不過多的說了。 我們還是接著看一下 JwtBearer 中間件,同樣它重寫了?HandleAuthenticateAsync?方法。
大致步驟如下:
讀取 Http Request Header 中的 Authorization 信息
讀取 Authorization 值里面的 Bearer 信息
驗證 Bearer 是否合法,會得到一個 ClaimsPrincipal
使用 ClaimsPrincipal 構(gòu)建一個 Ticket(票據(jù))
調(diào)用 Options.Events.TokenValidated(context),用戶可以重寫此方法驗證Token合法性
返回驗證成功
其他的知識點
這幾個中間件對會有對應(yīng)的 Options 配置項,在這些配置項中,都會有?AuthenticationScheme,?AutomaticAuthenticate,?AutomaticChallenge?這幾個屬性,那這幾個東西都是干嘛的呢?
AuthenticationScheme
我在?《ASP.NET Core 之 Identity 入門(二)》?一文中提到過這個知識點,當(dāng)時說很重要,這里可以看到了吧,每一種驗證中間件都會使用到這個東西,我比較偏向于把這個翻譯成 “認(rèn)證方案”。
我們知道,在 MVC 程序中一般通過在 Controller 或者 Action 上 打標(biāo)記(Attribute)的方式進(jìn)行授權(quán),最典型的就是新建一個項目的時候里面的AccountController。
[Authorize]public class AccountController : Controller{ }在 Authorize 這個 Attribute 中,有一個屬性叫做 ActiveAuthenticationSchemes 的東西,那么這個東西是干什么用的呢?
ActiveAuthenticationSchemes 就是對應(yīng)著中間件Options里面配置的 AuthenticationScheme ,如果你不指定的話,在使用多個身份驗證組件的時候會有問題,會有什么問題呢?往下看
AutomaticAuthenticate
AutomaticAuthenticate 很簡單,是一個bool類型的字段,用來配置是否處理 AuthenticationHandler 是否處理請求。或者你可以理解為中間件是不是自動的處理認(rèn)證相關(guān)的業(yè)務(wù)。
AutomaticChallenge
這個重要哦! 當(dāng)我們使用多個身份驗證中間件的時候,那么就要用到這個配置項了,該配置項是用來設(shè)置哪個中間件會是身份驗證流程中的默認(rèn)中間件,當(dāng)代碼運(yùn)行到 Controller 或者 Action 上的?[Authorize]?這個標(biāo)記的時候,就會觸發(fā)身份驗證流程。默認(rèn)情況下MVC的Filter會自動的觸發(fā)[Authorize],當(dāng)然也有一種手動觸發(fā)Authorize的辦法就是使用HttpContext.Authentication.ChallengeAsync()。
實際上,在驗證中間件的管道流程中,應(yīng)該只有一個組件被設(shè)定為?AutomaticChallenge = true,但其實大多數(shù)的中間件這個參數(shù)默認(rèn)都是 true ,這些中間件包括(Identity, Cookie, OAuth, OpenId, IISIntegration, WebListener)等, 這就導(dǎo)致了在整個驗證流程中會觸發(fā)多個中間件對其進(jìn)行相應(yīng),這種沖突大部分不是用戶期望的結(jié)果。
不幸的是,目前框架對于這種情況并沒有一個健壯的機(jī)制,如果開發(fā)人員對于這種機(jī)制不是很清楚的話,可能會造成很大的困擾。
幸運(yùn)的是,ASP.NET Core 團(tuán)隊已經(jīng)意識到了這個問題,他們將在 NET Standard 2.0 中對此重新進(jìn)行設(shè)計,比如手動觸發(fā)的時候應(yīng)該怎么處理,有多個的時候怎么處理,以及會添加一些語法糖。
目前情況下,當(dāng)有多個驗證中間件的時候,應(yīng)該怎么處理呢?比如同時使用 Identity 和 JwtBearer。正確的做法是應(yīng)該禁用掉除 Identity 以外的其他中間件的 AutomaticChallenge,然后指定調(diào)用的AuthenticationScheme。也就是說在Controller或者Action顯式指定?[Authorize(ActiveAuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]?,或者是可以指定一個策略來簡化授權(quán)調(diào)用?[Authorize("ApiPolicy")]
services.AddAuthorization(options => {options.AddPolicy("ApiPolicy", policy =>{policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);policy.RequireAuthenticatedUser();}); });而默認(rèn)不帶參數(shù)的?[Authorize]?可以指定AuthorizationPolicie:
services.AddAuthorization(options => {options.DefaultPolicy = new AuthorizationPolicyBuilder("Identity.Application").RequireAuthenticatedUser().Build(); });注意,手動調(diào)用?HttpContext.Authentication.ChallengeAsync()?不受 AuthorizationPolicie 影響。
總結(jié)
本篇介紹了 ASP.NET Core 有關(guān) Authentication 的幾個中間件,然后還有幾個比較重要的知識點,這篇文章內(nèi)容有點多,對于一些人來說可能需要一點時間消化。
相關(guān)文章:?
.NET Core中的認(rèn)證管理解析
ASP.NET Core 之 Identity 入門(一)
ASP.NET Core 之 Identity 入門(二)
ASP.NET Core 之 Identity 入門(三)
原文地址:http://www.cnblogs.com/savorboard/p/aspnetcore-authentication.html
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的ASP.NET Core 中的那些认证中间件及一些重要知识点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 权衡微服务
- 下一篇: .NET 使用 RabbitMQ 图文简