> 技术文档 > jwt 在net9.0中做身份认证

jwt 在net9.0中做身份认证

一、新建net9.0项目WebApplication1,安装包

    

在线生成TOKEN:JWT在线解码/编码工具 - 解析、验证、生成JSON Web Token 

Program.cs

using Microsoft.AspNetCore.Authentication.JwtBearer;using Microsoft.IdentityModel.Tokens;using Microsoft.OpenApi.Models;using System.Text;using System.Text.Json;var builder = WebApplication.CreateBuilder(args);// 配置 JWT 认证var secretKey = \"Tx7S/FjYAnh3LDpyOcysrZ0K6e2cWlIX4p8/X8xV2U0vqY4kbZ4EZFI8s0qc35T5Z80RbTkc0F/JE6UnQzwIcw==\";builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 显示详细的 PII 错误(仅限开发环境!) options.IncludeErrorDetails = true; // 👈 返回错误详情 options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)), ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = true, ClockSkew = TimeSpan.Zero }; // 捕获 JWT 验证事件 options.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { // 捕获验证失败的原因 Console.WriteLine($\"JWT 验证失败: {context.Exception.Message}\"); // 可以在这里返回自定义错误信息(但生产环境不建议返回详细错误) context.Response.StatusCode = 401; context.Response.ContentType = \"application/json\"; var errorMessage = new {  error = \"Unauthorized\",  message = context.Exception.Message // 返回具体错误信息 }; return context.Response.WriteAsync(JsonSerializer.Serialize(errorMessage)); }, OnChallenge = context => { // 当请求未提供 token 时触发 Console.WriteLine(\"请求未提供 JWT Token\"); return Task.CompletedTask; }, OnTokenValidated = context => { // Token 验证成功时触发 Console.WriteLine(\"JWT 验证成功\"); return Task.CompletedTask; } }; });// 配置 Swaggerbuilder.Services.AddSwaggerGen(c =>{ c.SwaggerDoc(\"v1\", new OpenApiInfo { Title = \"JWT Auth API\", Version = \"v1\" }); // 添加 JWT 认证支持到 Swagger c.AddSecurityDefinition(\"Bearer\", new OpenApiSecurityScheme { Description = \"JWT Authorization header using the Bearer scheme. Example: \\\"Authorization: Bearer {token}\\\"\", Name = \"Authorization\", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, Scheme = \"Bearer\" }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference {  Type = ReferenceType.SecurityScheme,  Id = \"Bearer\" } }, Array.Empty() } });}); builder.Services.AddCors(options =>{ options.AddPolicy(\"AllowAll\", policy => { policy.AllowAnyOrigin()  .AllowAnyMethod()  .AllowAnyHeader(); // 必须允许 Authorization 头 });});// 添加服务到容器builder.Services.AddControllers();var app = builder.Build();// 配置 HTTP 请求管道if (app.Environment.IsDevelopment()){ app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint(\"/swagger/v1/swagger.json\", \"JWT Auth API v1\"); });}app.UseCors(\"AllowAll\");app.UseAuthentication(); // 必须在 UseAuthorization 之前app.UseAuthorization();app.MapControllers();app.Run();

获取token:

AuthController

using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Mvc;using Microsoft.IdentityModel.Tokens;using System.IdentityModel.Tokens.Jwt;using System.Security.Claims;using System.Text;namespace JwtAuthApi.Controllers;[ApiController][Route(\"api/[controller]\")]public class AuthController : ControllerBase{ private readonly IConfiguration _configuration; public AuthController(IConfiguration configuration) { _configuration = configuration; } [HttpPost(\"login\")] [AllowAnonymous] public IActionResult Login([FromBody] LoginModel login) { // 这里应该有实际的用户验证逻辑 // 这里只是示例,直接接受任何用户名/密码 if (string.IsNullOrEmpty(login.Username)) { return BadRequest(\"Username is required\"); } // 创建 token var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.UTF8.GetBytes(\"Tx7S/FjYAnh3LDpyOcysrZ0K6e2cWlIX4p8/X8xV2U0vqY4kbZ4EZFI8s0qc35T5Z80RbTkc0F/JE6UnQzwIcw==\"); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString()), new Claim(ClaimTypes.Name, login.Username) }), Expires = DateTime.UtcNow.AddHours(1), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); var tokenString = tokenHandler.WriteToken(token); return Ok(new { Token = tokenString, ExpiresIn = (int)TimeSpan.FromHours(1).TotalSeconds }); }}public class LoginModel{ public string Username { get; set; } public string Password { get; set; }}

WeatherForecastController.cs

using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Mvc;namespace JwtAuthApi.Controllers;[ApiController][Route(\"[controller]\")]public class WeatherForecastController : ControllerBase{ private static readonly string[] Summaries = new[] { \"Freezing\", \"Bracing\", \"Chilly\", \"Cool\", \"Mild\", \"Warm\", \"Balmy\", \"Hot\", \"Sweltering\", \"Scorching\" }; [HttpGet] [Authorize] // 需要认证 public IEnumerable Get() { // 可以从 User 中获取 JWT 中的声明 var userName = User.Identity?.Name; var userId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; Console.WriteLine($\"User {userName} (ID: {userId}) accessed weather forecast\"); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); }}public class WeatherForecast{ public DateTime Date { get; set; } public int TemperatureC { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); public string? Summary { get; set; }}