一、JWT概述
JSON Web Token(JWT)是一種輕量級的身份認證機制,廣泛應用于分布式系統中的用戶認證。它通過緊湊的JSON格式存儲用戶身份信息,并使用數字簽名確保信息的完整性和真實性。與傳統的基于Session的認證相比,JWT具有無狀態、可擴展、跨平臺等優勢,特別適合于微服務架構和前后端分離的應用場景。
JWT的核心優勢在于:
無狀態:服務器不需要存儲會話信息,減輕服務器負擔
跨平臺:基于標準JSON格式,可在不同語言和平臺間傳遞
自包含:令牌包含所有必要的用戶信息,減少數據庫查詢
可擴展:支持自定義聲明,滿足不同業務需求
安全性:通過數字簽名確保信息不被篡改
二、JWT工作原理
JWT認證的核心流程如下:
用戶登錄:用戶提供用戶名和密碼進行登錄
生成Token:服務器驗證成功后,生成包含用戶身份信息的JWT令牌
返回Token:服務器將JWT令牌返回給客戶端
存儲Token:客戶端存儲JWT令牌(通常存儲在localStorage或Cookie中)
請求攜帶Token:客戶端后續請求時,在HTTP頭部攜帶JWT令牌
驗證Token:服務器驗證JWT令牌的有效性(簽名驗證、過期時間檢查等)
處理請求:驗證通過后,服務器處理請求并返回結果
JWT認證流程圖
+----------+ ? ? 登錄請求 ? ? +----------+ | ? ? ? ? | --------------> | ? ? ? ? | | 客戶端 ? | ? ? ? ? ? ? ? ? ? | 服務器 ? | | ? ? ? ? | <-------------- | ? ? ? ? | +----------+ ? 返回JWT令牌 ? ? +----------+| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? || ? 攜帶JWT令牌的請求 ? ? ? ? ? ? ? || -----------------------------> || ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? || <----------------------------- || ? ? ? 處理后的響應 ? ? ? ? ? ? ? |v ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? v
三、JWT結構組成
JWT令牌由三部分組成,用小數點(.)分隔,格式為Header.Payload.Signature:
1. Header(頭部)
Header部分包含令牌類型(typ)和加密算法(alg),通常如下:
{"alg": "HS256","typ": "JWT" }
其中,alg表示使用的加密算法(如HS256、RS256等),typ表示令牌類型。
2. Payload(載荷)
Payload部分包含用戶身份信息和其他元數據,分為標準聲明和自定義聲明:
標準聲明:
iss:令牌頒發者
sub:令牌主題(通常是用戶ID)
aud:令牌受眾
exp:令牌過期時間
iat:令牌頒發時間
nbf:令牌生效時間
jti:令牌唯一標識符
自定義聲明:根據業務需求定義的字段,如用戶角色、權限等。
示例:
{"sub": "1234567890","name": "John Doe","role": "admin","exp": 1678900000 }
3. Signature(簽名)
Signature部分是對Header和Payload的簽名,用于驗證令牌的完整性和真實性。服務器使用Header中指定的算法,結合密鑰對Header和Payload進行簽名:
PlainText HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secretKey )
四、C#中實現JWT認證
1. 安裝必要的包
在C#項目中,我們需要安裝以下NuGet包:
System.IdentityModel.Tokens.Jwt:用于生成和驗證JWT令牌
Microsoft.AspNetCore.Authentication.JwtBearer:提供JWT身份驗證中間件
Install-Package System.IdentityModel.Tokens.Jwt Install-Package Microsoft.AspNetCore. Authentication.JwtBearer
2. 配置JWT認證服務
在Program.cs文件中,添加JWT認證服務配置:
Program.cs using Microsoft.AspNetCore.Authentication. JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; ? var builder = WebApplication.CreateBuilder(args); ? // 添加JWT認證服務 builder.Services.AddAuthentication (JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>{options.TokenValidationParameters = new TokenValidationParameters{ValidateIssuer = true, // 驗證頒發者ValidateAudience = true, // 驗證受眾ValidateLifetime = true, // 驗證過期時間ValidateIssuerSigningKey = true, // 驗證簽名密鑰ValidIssuer = builder.Configuration["Jwt:Issuer"], // 頒發者ValidAudience = builder.Configuration["Jwt:Audience"], // 受眾IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"])) // 簽名密鑰};}); ? // 添加授權服務 builder.Services.AddAuthorization(); ? var app = builder.Build(); ? // 使用認證和授權中間件 app.UseAuthentication(); app.UseAuthorization(); ? app.MapControllers(); app.Run();
3. 配置appsettings.json
在appsettings.json文件中添加JWT相關配置:
appsettings.json 應用 {"Jwt": {"Issuer": "YourIssuer","Audience": "YourAudience","SecretKey": "YourSecretKeyHereShouldBeLongEnough"},"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHosts": "*" }
4. 生成JWT令牌
創建一個AuthController,實現用戶登錄和生成JWT令牌的功能:
AuthController.cs ? using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; ? [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase {private readonly IConfiguration _configuration; ?public AuthController(IConfiguration configuration){_configuration = configuration;} ?[HttpPost("login")]public IActionResult Login([FromBody] LoginRequest request){// 驗證用戶憑據(實際應用中應查詢數據庫)if (request.Username == "admin" && request.Password == "password"){// 創建用戶聲明var claims = new[]{new Claim(ClaimTypes.Name, request.Username),new Claim(ClaimTypes.Role, "admin"),new Claim(JwtRegisteredClaimNames.Sub, "1234567890"),new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())}; ?// 生成對稱安全密鑰var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"])); ?// 生成簽名憑據var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); ?// 創建JWT令牌var token = new JwtSecurityToken(issuer: _configuration["Jwt:Issuer"],audience: _configuration["Jwt:Audience"],claims: claims,expires: DateTime.Now.AddMinutes(30),signingCredentials: creds); ?// 返回JWT令牌return Ok(new{token = new JwtSecurityTokenHandler().WriteToken(token),expiration = token.ValidTo});} ?return Unauthorized();} } ? public class LoginRequest {public string Username { get; set; }public string Password { get; set; } }
5. 保護API端點
使用[Authorize]屬性保護API端點,只有攜帶有效JWT令牌的請求才能訪問:
ValuesController.cs ? using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; ? [ApiController] [Route("api/[controller]")] [Authorize] public class ValuesController : ControllerBase {[HttpGet]public IActionResult Get(){return Ok(new string[] { "value1", "value2" });} ?[HttpGet("{id}")][Authorize(Roles = "admin")]public IActionResult Get(int id){return Ok($"value {id}");} }
五、JWT認證的注意事項
密鑰安全:確保JWT密鑰安全存儲,避免硬編碼在代碼中
令牌過期時間:設置合理的令牌過期時間,平衡安全性和用戶體驗
HTTPS傳輸:使用HTTPS協議傳輸JWT令牌,防止中間人攻擊
令牌刷新機制:實現令牌刷新機制,避免用戶頻繁登錄
敏感信息:不要在JWT中存儲敏感信息,如密碼等
權限控制:結合角色和權限聲明,實現細粒度的訪問控制