jwt 在net9.0中做身份认证

发布于:2025-07-26 ⋅ 阅读:(14) ⋅ 点赞:(0)

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

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.7" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
  </ItemGroup>

在线生成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;
            }
        };
    });

// 配置 Swagger
builder.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<string>()
        }
    });
}); 

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<WeatherForecast> 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; }
}


网站公告

今日签到

点亮在社区的每一天
去签到