日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

ASP.NET Core 基于角色的 JWT 令牌

發布時間:2023/12/4 asp.net 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core 基于角色的 JWT 令牌 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文:https://bit.ly/3vYljq3
作者:Rick Strahl
翻譯:精致碼農-王亮
聲明:我翻譯技術文章不是逐句翻譯的,而是根據我自己的理解來表述的。其中可能會去除一些本人實在不知道如何組織但又不影響理解的句子。

ASP.NET Core 中的認證和授權仍然是配置中最麻煩的組件。似乎幾乎在每一個應用程序上,我都會遇到一些與 Auth 有關的問題。四個版本帶來了三種不同的身份驗證實現,功能的更新也留下了一大波過時的信息。今天,我看著 Web API 基于角色 JWT 授權認證的過時信息,陷入了一個土撥鼠日(譯注:形容不斷重復的日子)的循環中。

目前在 ASP.NET Core 中的 JWT 令牌(Token)配置實際上非常好用,只要你把正確的配置咒語串起來。Auth 配置的部分問題是,大多數配置只需按固定的“儀式”進行操作。例如,設置Issuer和Audience我們似乎完全不需要關心它們是什么,但它們是 JWT 令牌要求的一部分,確實需要配置。幸運的是,這些設置中只有少數幾個是真正需要的,大部分都是模板。

在這篇文章中,我具體講一下:

  • ASP.NET Core Web API 的認證

  • JWT 令牌的使用

  • 基于角色授權

  • 只使用底層功能--不使用 ASP.NET Core Identity

配置

認證(Authentication)和授權(Authorization)在 ASP.NET Core 中作為中間件提供,你必須在ConfigureServices()中配置它們,并在Configure()中連接中間件。

配置 JWT 認證和授權

第一步是在Startup文件中的ConfigureServices()中配置認證(Authentication)。在這里添加 JWT 令牌配置,并將所需組件添加到 ASP.NET Core 的處理管道中:

// in ConfigureServices()// config shown for reference values config.JwtToken.Issuer = "https://mysite.com"; config.JwtToken.Audience = "https://mysite.com"; config.JwtToken.SigningKey = "12345@4321"; // some long id// Configure Authentication services.AddAuthentication( auth=> {auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => {options.SaveToken = true;options.TokenValidationParameters = new TokenValidationParameters{ValidateIssuer = true,ValidIssuer = config.JwtToken.Issuer,ValidateAudience = true,ValidAudience = config.JwtToken.Audience,ValidateIssuerSigningKey = true,IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.JwtToken.SigningKey))}; }

JWT 認證有一堆的設置,其中大部分是足夠神秘的,所以我幾乎只是將它們復制和粘貼。我只想說,這些設置大多是關于設置協議和令牌包裝器(Wrapper)的。通常情況下,我將這些值存儲在我的應用程序的配置中,這樣它就會通過 .NET 配置 Provider 提取進來,而上面的config就是那個特定的配置實例。

在這個全局配置中沒有什么是針對角色的。所有基于角色的相關配置都發生在后面的認證(Authenticate)端點中創建令牌的時候。

令牌和哈希如何工作

在進入這里之前,我們先來回顧一下基于令牌的身份驗證是如何工作的,以及這些設置值是如何融入這個方案的。

上面的設置值配置了令牌的常用值和用于簽署令牌的密鑰。它們提供身份識別標記,以確保生成的令牌是唯一的。我認為這些值是一個基本的令牌包裝,通常在你驗證用戶后,當你創建令牌并將令牌作為 Web 請求的一部分提供給用戶之時,你將向令牌添加你的自定義、應用特定的?Claim,。

IssuerSigningKey是這個配置中最重要的部分,它用于將最終的令牌與包裝器以及任何添加的聲明進行哈希(Hash)。該哈希值用于驗證令牌的真實性。請注意,雖然生成的令牌被編碼為 Base64,但它本身并不安全,即使在客戶端,內容也可以被解碼。也就是說,你可以將任何 JWT 令牌粘貼到 JWT.io 這個網站中,對令牌的內容進行解碼。

哈希確保了令牌不能被改變。當令牌與請求一起發送時,它將由 ASP.NET Core 的 JWToken 中間件進行驗證,它首先根據令牌數據驗證哈希值,然后根據包含的授權信息進行認證/授權。如果客戶端或其他實體以任何方式更改了令牌,則哈希值將無法驗證通過,會被直接拒絕。之后在中間件管道的授權部分進行用戶名和角色等的匹配。

添加 Auth 中間件

接下來我們需要在Startup文件的Configure中使用app.UseAuthentication()和app.UseAuthorization()添加實際的中間件:

// in Startup.Configure() app.UseHttpsRedirection(); app.UseRouting();// *** These are the important ones - note order matters *** app.UseAuthentication(); app.UseAuthorization();app.UseStatusCodePages(); //app.UseDefaultFiles(); // so index.html is not required //app.UseStaticFiles();app.UseEndpoints(endpoints => {endpoints.MapControllers(); });

請注意,順序對于認證(Authentication)和授權(Authorization)很重要。這兩個需要在?Routing 之后但在任何?HTTP 輸出中間件之前添加,最重要的是在app.UseEndpoints()之前。

使用 Web API 端點認證用戶

接下來,我們需要在應用程序中通過詢問憑證來驗證用戶,然后生成一個令牌并將其返回給 API 客戶端。

這很可能發生在 Controller 的 Action 方法或中間件端點處理程序中。下面是使用 Controller 的 Action 方法示例:

[AllowAnonymous] [HttpPost] [Route("authenticate")] public?object?Authenticate(AuthenticateRequestModel loginUser) {// My application logic to validate the user// returns a user entity with Roles collectionvar bus = new AccountBusiness();var user = bus.AuthenticateUser(loginUser.Username, loginUser.Password);if (user == null)throw?new ApiException("Invalid Login Credentials: " + bus.ErrorMessage, 401);var claims = new List<Claim>();claims.Add(new Claim("Username",loginUser.Username));claims.Add(new Claim("DisplayName",loginUser.Name));// Add roles as multiple claimsforeach(var role in user.Roles){claims.Add(new Claim(ClaimTypes.Role, role.Name));}// Optionally add other app specific claims as neededclaims.Add(new Claim("UserState", UserState.ToString()));// create a new token with token helper and add our claim// from `Westwind.AspNetCore` NuGet Packagevar token = JwtHelper.GetJwtToken(loginUser.Username,Configuration.JwtToken.SigningKey,Configuration.JwtToken.Issuer,Configuration.JwtToken.Audience,TimeSpan.FromMinutes(Configuration.JwtToken.TokenTimeoutMinutes),claims.ToArray());return?new{token = JwtHelper.GetJwtTokenString(token),expires = token.ValidTo}; }

我正在使用一個JwtHelper類來實際生成一個令牌,這樣我就不必在每個應用中記住JwtHelper類實現的這個重復的“儀式”。這段代碼創建了令牌,并從中提取了一個字符串,準備作為承載令牌值返回。下面是這個類的完整代碼:

public?class?JwtHelper {///?<summary>/// Returns a Jwt Token from basic input parameters///?</summary>public?static JwtSecurityToken GetJwtToken(string username,string uniqueKey,string issuer,string audience,TimeSpan expiration,Claim[] additionalClaims = null){var claims = new[]{new Claim(JwtRegisteredClaimNames.Sub,username),new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())};if (additionalClaims is?object){var claimList = new List<Claim>(claims);claimList.AddRange(additionalClaims);claims = claimList.ToArray();}var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(uniqueKey));var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);return?new JwtSecurityToken(issuer: issuer,audience: audience,expires: DateTime.UtcNow.Add(expiration),claims: claims,signingCredentials: creds);}///?<summary>/// Returns a token string from base claims///?</summary>public?static?string?GetJwtTokenString(string username,string uniqueKey,string issuer,string audience,TimeSpan expiration,Claim[] additionalClaims = null){var token = GetJwtToken(username, uniqueKey, issuer, audience, expiration, additionalClaims);return?new JwtSecurityTokenHandler().WriteToken(token);}///?<summary>/// Converts an existing Jwt Token to a string///?</summary>public?static?string?GetJwtTokenString(JwtSecurityToken token){return?new JwtSecurityTokenHandler().WriteToken(token);}///?<summary>/// Returns an issuer key///?</summary>public?static SymmetricSecurityKey GetSymetricSecurityKey(string issuerKey){return?new SymmetricSecurityKey(Encoding.UTF8.GetBytes(issuerKey));} }

Controller 的Authenticate()代碼首先使用一個應用程序特定的業務對象來驗證用戶,用戶登錄信息作為 API 調用的一部分傳入該方法(比如 HTML 網頁的登錄表單)。如果用戶是有效的,我就創建新的 Claim,這些 Claim 被打包到令牌中。

令牌包括用戶名和角色,這是 ASP.NET Core 授權工作所需的內容。然后,如果有必要,我可以添加一些額外的應用程序特定的 Claim,比如上面例子中的DisplayName和自定義UserState對象。這些聲明會隨令牌一起,以便在后續請求提取,而不必再訪問后端數據庫檢索它們。

最后,使用JwtHelper的GetJwtToken()生成令牌,并使用GetJwtTokenString()將令牌轉換為字符串,這個字符串將被客戶端放在請求頭中攜帶到后臺服務端。

請注意,要確保可以匿名訪問?Authentication?方法。如果 Controller 標注了?[Authorize]?特性,則需要在Authenticate()方法上標注[AllowAnonymous]特性。

Claim 和角色

ASP.NET Core 使用 Claim 進行認證。Claim 是你可以存儲在令牌中的數據片段,這些數據與令牌一起攜帶,并可以從令牌中讀取。對于授權來說,角色可以作為 Claim。

在 .NET Core 3.1 和 5.x 中,為授權添加 ASP.NET Core 角色識別的正確語法是,為每個角色添加多個 Claim:

// Add roles as multiple claims foreach(var role in user.Roles) {claims.Add(new Claim(ClaimTypes.Role, role.Name));// these also work - and reduce token size// claims.Add(new Claim("roles", role.Name));// claims.Add(new Claim("role", role.Name)); }

訪問生成 JWT 令牌的 API

到這,我已經有了一個用于認證的 API 端點,我可以從這個端點上獲取一個令牌。下面是這個請求的樣子:

傳入用戶名和密碼,則會返回令牌和到期時間。你可以在 jwt.io 查看這個令牌和它生成的內容:

請注意,該令牌很容易被外部工具解碼,與我的應用程序完全無關。這意味著所包含的令牌數據是不安全的。然而,除非數據由原始的簽名密鑰簽名,否則無法更改該令牌中的值并提供給服務器應用程序。這可以防止令牌被篡改。

一旦生成了令牌并發送給客戶端,客戶端就可以在后續的請求中使用它來添加相應的授權請求頭:

Authorization: Bearer 123456******

確保 API 的安全

現在剩下的就是通過在 Controller 或端點方法上添加[Authorize]特性來選擇性或限制對 API 的訪問。

我可以使用以下特性之一,或者完全不使用特性(對于開放訪問):

  • 普通的[Authorize]讓任何經過認證的用戶進入

  • 基于角色的[Authorize(Roles = "Administrator,ReportUser")]訪問

  • 允許匿名[AllowAnonymous]訪問

請注意,這些特性可以在 Controller 類或 Action 方法上標注,而且它們是自上而下分層工作的,所以一個類屬性適用于所有的 Action 方法。這就是?[AllowAnonymous]?的用武之地,它可以覆蓋一兩個可能需要開放訪問的請求(如Authenticate()或Logout())。

要為任何登錄用戶設置授權,只需使用[Authorize]即可:

[Authorize] // just require ANY authentication [Route("/api/v1/lookups")] public?class?IdLookupController : BaseApiController

在這種情況下,你可能需要對用戶進行一些額外的驗證,以確保你有正確的用戶進行特定的操作。

要設置特定角色的限制,你可以使用Roles參數:

[Authorize(Roles = "Administrator")] [HttpPost] [Route("customers")] public?async Task<SaveResponseModel> SaveCustomer(IdvCustomer model)

現在只有那些屬于 Administrator 組的人有訪問權。角色可以是使用逗號分隔的列表,如使用“Administrator, ReportUser”來允許多個角色訪問。

使用令牌訪問安全端點

現在 API 已經安全了,我們必須在每個請求中傳遞 Bearer 令牌來進行驗證。它看起來像這樣:

瞧,我現在可以訪問管理員組保護的 POST 操作了。

這就完成了一個閉環...

總結

在最近的版本中,ASP.NET Core 中的身份驗證和授權已經變得簡單了很多,但是要找到正確的文檔來設置 JWT 令牌身份驗證的所有相關信息仍然不易。關于身份驗證的信息很多,很容易在文檔中迷失方向,并最終可能選擇過時的信息,因為在整個 ASP.NET Core 版本中,身份驗證的行為已經發生了重大變化。(基于本文)如果你要查找額外的信息,請確保它是 3.1 及以后的版本。

在這篇文章中,我已經解決了 3.1 和 5.0 版本的問題。值得慶幸的是,5.0 沒有看到對認證/授權 API 的進一步破壞性改變。

通常情況下,我寫下這篇文章是為了讓我自己安心,這樣我就能在一個地方得到所有的信息。希望你們中的一些人也會覺得這很有用。

-

想第一時間看到更新推送,請幫忙點點『贊』和『在看』

總結

以上是生活随笔為你收集整理的ASP.NET Core 基于角色的 JWT 令牌的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。