阿杰,我给你详细讲一下 ASP.NET Core Web API 中 Token 验证 的实现,从原理到代码一步步来,让你能直接在项目中落地。


1. Token 验证的基本思路

在 Web API 中,Token 验证通常指 客户端拿到一个令牌(Token)后,每次请求都在 HTTP Header 中携带它,服务端验证 Token 是否有效

常见 Token 类型:

  • JWT (JSON Web Token) ✅ 主流,跨平台支持好
  • 自定义加密 Token(适合简单场景)
  • OAuth2 Access Token(更复杂的授权系统)

这里我用 JWT 举例,因为它是 ASP.NET Core 的标准做法。


2. JWT 验证流程

  1. 用户登录 → 服务器验证账号密码 → 生成 JWT → 返回给客户端
  2. 客户端发起请求 → 在 Authorization 请求头里带上: Authorization: Bearer <token>
  3. 服务器验证 JWT → 如果有效,解析出用户信息 → 允许访问

3. 安装 NuGet 包

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package System.IdentityModel.Tokens.Jwt

4. 生成 JWT Token

Services 中写一个 JwtHelper

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.Text;

public class JwtHelper
{
    private readonly string _key = "your_secret_key_here"; // 存到配置文件更安全
    private readonly string _issuer = "yourapp";
    private readonly string _audience = "yourapp_users";

    public string GenerateToken(string username, string role, int expireMinutes = 60)
    {
        var claims = new[]
        {
            new Claim(ClaimTypes.Name, username),
            new Claim(ClaimTypes.Role, role)
        };

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_key));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: _issuer,
            audience: _audience,
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(expireMinutes),
            signingCredentials: creds
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

5. 配置 JWT 验证

Program.cs

var builder = WebApplication.CreateBuilder(args);

var key = "your_secret_key_here"; // 应该从配置文件读取

builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = "yourapp",
            ValidateAudience = true,
            ValidAudience = "yourapp_users",
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)),
            ClockSkew = TimeSpan.Zero // 去掉默认的5分钟缓冲
        };
    });

builder.Services.AddAuthorization();
builder.Services.AddControllers();

var app = builder.Build();

app.UseAuthentication(); // 必须放在 UseAuthorization 之前
app.UseAuthorization();

app.MapControllers();
app.Run();

6. 登录接口(颁发 Token)

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly JwtHelper _jwt;

    public AuthController(JwtHelper jwt)
    {
        _jwt = jwt;
    }

    [HttpPost("login")]
    public IActionResult Login([FromBody] LoginRequest request)
    {
        // 假设这里验证用户名密码
        if (request.Username == "admin" && request.Password == "123456")
        {
            var token = _jwt.GenerateToken(request.Username, "Admin");
            return Ok(new { token });
        }

        return Unauthorized("用户名或密码错误");
    }
}

public class LoginRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}

7. 受保护的 API

[ApiController]
[Route("api/[controller]")]
public class ValuesController : ControllerBase
{
    [HttpGet]
    [Authorize] // 需要携带有效 Token 才能访问
    public IActionResult Get()
    {
        var username = User.Identity.Name;
        var role = User.FindFirst(ClaimTypes.Role)?.Value;
        return Ok(new { message = $"欢迎 {username},角色:{role}" });
    }
}

8. 客户端请求示例

  1. 登录获取 Token
POST /api/auth/login
{
  "username": "admin",
  "password": "123456"
}

返回:

{
  "token": "eyJhbGciOiJIUzI1NiIs..."
}
  1. 携带 Token 访问受保护 API
GET /api/values
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

9. 最佳实践

  • 密钥管理:密钥存到配置文件(appsettings.json)或环境变量,不要写死代码。
  • Token 过期刷新:可以加 Refresh Token 机制。
  • 角色/权限控制:配合 [Authorize(Roles="Admin")] 做细粒度控制。
  • HTTPS:生产环境必须用 HTTPS,防止 Token 被窃取。
  • 前端存储 Token:推荐存到 localStoragesessionStorage,不要放 Cookie(除非做 HttpOnly)。