.net 8 实现 JWT 无状态设计 token [附源码]
本文主要分為兩個部分:
1、概念
2、.net 8 demo
第一部分主要描述所有與 JWT 相關的概念以及詞匯,及其原理;第二部分是代碼示例,文末附 源碼下載。
* 閱讀提示 :鼠標懸停在 章節標題 上可見 文章目錄
1、概念
|
JWT |
json web token 是一種開放標準(RFC 7519),是指定一種數據格式(json) 和數據結構 (header, payload, signature) , 用于網絡應用間信息傳輸,一般是用于客戶端與服務器之間的安全校驗 |
|
authentication |
鑒權;可以為用戶創建 token,可以校驗 token 有效性 |
|
authorization |
批準 / 授權;是一種配置,約束訪問條件,例如: [Authorize(Roles = "Admin")] // 管理員才可訪問 [Authorize(Policy = "EmployeeWithDepartment")] // 符合特定策略才可訪問 |
|
bearer |
持票人,使用場景在于請求時,header 的格式 例如請求頭部的參數 "Authorization" : "Bearer tokenString" |
一個 token 由 3 個部分組成,并且以實心句號 . 分割,以下為一個 token 示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidXNlcjEyMyIsIm5iZiI6MTczMTM5MzYzNiwiZXhwIjoxNzMxMzk3MjM2LCJpYXQiOjE3MzEzOTM2MzYsImlzcyI6InlvdXJkb21haW4uY29tIiwiYXVkIjoieW91ci1hcGktYXVkaWVuY2UifQ.q2zUeZ3RAVIxg5CVNI2Pjq9Nfvue3_tCQagDRJmStYI
|
token part |
decode (by base64) |
remark |
|
|
header |
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 |
{ "alg" : "HS256", "typ" : "JWT" } |
token metadata 說明用于加密的算法類型 |
|
payload (有效載荷) |
eyJuYW1lIjoidXNlcjEyMyIsIm5iZiI6MTczMTM5MzYzNiwiZXhwIjoxNzMxMzk3MjM2LCJpYXQiOjE3MzEzOTM2MzYsImlzcyI6InlvdXJkb21haW4uY29tIiwiYXVkIjoieW91ci1hcGktYXVkaWVuY2UifQ
|
{ "name": "user123", "nbf": 1731393636, "exp": 1731397236, "iat": 1731393636, "iss": "yourdomain.com", "aud": "your-api-audience" } |
自定義的用戶信息(claims), 以及一些必要信息: nbf : not before, token 生效時間 exp : expiration time, token 過期時間 iat : issued at 簽發時間 iss : issuer of the token 簽發者(比如服務端名字) aud : audience,該 token 的受眾,可以是服務名稱 或者 api 名稱等等 |
|
signature |
q2zUeZ3RAVIxg5CVNI2Pjq9Nfvue3_tCQagDRJmStYI |
N/A |
signature:是根據 header 中指定的算法以及在服務端密鑰,對 payload 加密得到的哈希值; 用于服務端校驗 token 是否簽發自服務端。 (請求時 token 的 payload 與解密 signature 后得到的payload 需要一致,所以擅改 payload 會導致token 無效) |
* base64 transfer online : Base64編碼_base64在線解碼_base64加密在線轉換
什么是無狀態化?
|
無狀態 (stateless) :指服務端不需要存儲任何關于用戶會話的信息。 一般地,在舊時的實現方式中,服務端可能需要存儲用戶登錄的記錄,例如需要存儲對應用戶會話的有效時間。 而 JWT 標準中 signature 的設計允許了服務端可以不對登錄信息做持久化,服務端可以通過算法驗證 signature 的有效性,以此確保了 token 的安全性,所以并不需要另外存儲用戶會話狀態,這樣就減少服務端壓力和復雜性,做到“無狀態”化。 但其實現今的應用需求中,很多時候都希望追蹤到用戶行為,所以還是會 log 用戶操作,為日后的用戶行為分析做數據奠基;當然,這是另一個話題。 |
2、.net 8 demo
2.1 Authentication
包引用
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
創建 token 的方法
1 public string GenerateJwtToken(string userName)
2 {
3
4 var tokenHander = new JwtSecurityTokenHandler();
5 var key = Encoding.ASCII.GetBytes("your secret key");
6 var tokenDescriptor = new SecurityTokenDescriptor
7 {
8 // configure the custome information in the Claim instance
9 Subject = new System.Security.Claims.ClaimsIdentity(new[] { new Claim("name", userName) }),
10
11 // configure the expiration time
12 Expires = DateTime.UtcNow.AddHours(1),
13
14 // issuer could be your service name or other, and it will be the [iss] of the token
15 Issuer = "xx Servicing",
16
17 // audience could be the audience of your service, and it will be the [aud] of the token
18 Audience = "your api audience",
19
20 // configure secret algorithm and secret key for signature part
21 SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
22
23 };
24
25 var token = tokenHander.CreateToken(tokenDescriptor);
26 return tokenHander.WriteToken(token);
27 }
驗證 token 的配置
1 builder.Services.AddAuthentication(options =>
2 {
3 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
4 options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
5 })
6 .AddJwtBearer(options =>
7 {
8 options.TokenValidationParameters = new TokenValidationParameters
9 {
10 // validate the token expiration
11 ValidateLifetime = true,
12
13 // validate signature
14 ValidateIssuerSigningKey = true,
15
16 // need to sure the issuer/audience value here is same with the issuer/audience while token generating
17 ValidateIssuer = true,
18 ValidateAudience = true,
19 ValidIssuer = "yourdomain.com",
20 ValidAudience = "your-api-audience",
21
22 //ValidateIssuer = false, // Skip issuer validation
23 //ValidateAudience = false, // Skip audience validation
24
25 IssuerSigningKey = new SymmetricSecurityKey("your secret key"),
26 ClockSkew = TimeSpan.FromMinutes(5) // Allow for clock skew
27
28 };
29
30 });
開啟 authentication 和 authorization
1 app.UseAuthentication();
2 app.UseAuthorization();
!注意:
1、此處的 Authentication,Authorization 都是 Miscroft.AspNetCore 自帶的中間件。
2、Authentication 是鑒權,Authorization 是授權 / 批準,這兩個中間件的位置不能錯,必須是:鑒權在前。
|
Authentication 中間件主要負責驗證 token ,比如檢查簽名是否正確,檢查 token 有效期。 當 Authentication 中間件成功驗證令牌后,它會將 token 中的用戶信息(像是用戶ID、角色等)寫入到 httpContext,再傳遞給 Authorization 中間件。此時,Authorization 會拿到有效的 httpContext.User 屬性,這是一個 ClaimsPrincipal 對象,包含了用戶信息聲明(claims); 若繞開了 Authentication 中間件,httpContext 直接到 Authorization ,此時會找不到合法的 httpContext.User,所以返回 401 Unauthorized 錯誤。 |
源碼下載
1、.net 8 AuthDemo Web Api Project
2、AuthDemo.postman_collection.json
2.2 Authorization
2.2.1 Authorize
1 // 標注 Authorize 后訪問該api時會驗證token
2 [Authorize]
3 [HttpGet("GetList")]
4 public IEnumerable<WeatherForecast> GetList()
5 {
6 ..
7 }
2.2.2 Policy 策略
1 // 在 Startup.cs 中配置策略
2 services.AddAuthorization(options =>
3 {
4 options.AddPolicy("Over18", policy =>
5 policy.RequireClaim("Age", "18")); // 驗證 token 中的 age 參數是否等于 18
6 });
7
8 // 在 Controller 中使用策略
9 [Authorize(Policy = "Over18")]
10 public IActionResult RestrictedContent()
11 {
12 ..
13 }
1 // 驗證 token 中的 role 參數是否 ("Admin", "Manager")中的成員,注:大小寫敏感
2 services.AddAuthorization(options =>
3 {
4 options.AddPolicy("AdminOrManager", policy =>
5 policy.RequireRole("Admin", "Manager"));
6 });
7
8 // 多個“并且”條件的聲明
9 services.AddAuthorization(options =>
10 {
11
12 options.AddPolicy("EmployeeWithDepartment", policy =>
13 policy.RequireClaim("EmployeeNumber")
14 .RequireClaim("Department", "HR", "IT"));
15 });
2.2.3 AllowAnonymous
[Authorize] 可以修飾在 controller 上,這意味著該 controller 下的所有 api 都需要驗證token,
此時可以通過修飾 [AllowAnonymous] 特別指定某一個 api 不需要 token 驗證。
1 [Authorize]
2 public class AccountController : Controller
3 {
4 [AllowAnonymous]
5 public IActionResult Login()
6 {
7 ..
8 }
9
10 public IActionResult Logout()
11 {
12 ..
13 }
14 }
博客園的編輯器也太難用了吧!!
2024-11-13
總結
以上是生活随笔為你收集整理的.net 8 实现 JWT 无状态设计 token [附源码]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue+elementui怎样点击tab
- 下一篇: C# 搭建一个 基于ISqlSugarC