C#中如何运用JWT用户认证
一、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中存储敏感信息,如密码等
权限控制:结合角色和权限声明,实现细粒度的访问控制