JWT(JSON Web Token)是无状态的登录授权方案,适合前后端分离、微服务项目,无需存储 Session,仅靠 Token 完成身份验证。
下面带你一步步实现 .NET 6/7/8 + JWT 登录、颁发 Token、接口授权验证。
一、核心流程
- 用户输入账号密码 → 后端验证
- 验证通过 → 生成 JWT Token 返回给前端
- 前端存储 Token(localStorage/cookie)
- 前端请求接口时 → 请求头携带
Authorization: Bearer Token - 后端验证 Token 有效性 → 允许/拒绝访问
二、环境准备
- 创建 ASP.NET Core Web API 项目
- 安装 JWT 必需 NuGet 包:
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
三、完整实现代码
1. 配置 JWT 参数(appsettings.json)
{
"JwtSettings": {
"SecretKey": "YourLongSecretKeyHere_1234567890abcdef", // 密钥(越长越安全)
"Issuer": "MyServer", // 签发者
"Audience": "MyClient", // 接收者
"ExpireMinutes": 60 // Token 过期时间(分钟)
}
}
2. 创建 JWT 配置实体类
namespace JwtDemo
{
public class JwtSettings
{
public string SecretKey { get; set; } = string.Empty;
public string Issuer { get; set; } = string.Empty;
public string Audience { get; set; } = string.Empty;
public int ExpireMinutes { get; set; }
}
}
3. Program.cs 注册 JWT 认证服务(核心配置)
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// 1. 读取 JWT 配置
var jwtSettings = builder.Configuration.GetSection("JwtSettings").Get<JwtSettings>();
builder.Services.AddSingleton(jwtSettings); // 注入配置
// 2. 添加控制器
builder.Services.AddControllers();
// 3. 注册 JWT 认证
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true, // 验证签发者
ValidateAudience = true, // 验证接收者
ValidateLifetime = true, // 验证过期时间
ValidateIssuerSigningKey = true, // 验证签名密钥
ValidIssuer = jwtSettings.Issuer,
ValidAudience = jwtSettings.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey))
};
});
var app = builder.Build();
// 4. 启用认证 + 授权中间件(顺序不能错!)
app.UseAuthentication(); // 先认证
app.UseAuthorization(); // 后授权
app.MapControllers();
app.Run();
4. 创建登录接口 + Token 生成服务
登录请求模型
namespace JwtDemo.Models
{
public class LoginRequest
{
public string UserName { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
}
登录控制器(生成 JWT Token)
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using JwtDemo.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace JwtDemo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AccountController : ControllerBase
{
private readonly JwtSettings _jwtSettings;
// 注入 JWT 配置
public AccountController(JwtSettings jwtSettings)
{
_jwtSettings = jwtSettings;
}
/// <summary>
/// 登录接口:验证账号密码,生成 Token
/// </summary>
[HttpPost("login")]
public IActionResult Login(LoginRequest request)
{
// 1. 模拟数据库验证账号密码(实际项目替换为真实校验)
if (request.UserName != "admin" || request.Password != "123456")
{
return Unauthorized("账号或密码错误");
}
// 2. 创建用户声明(存储用户信息:ID、角色、权限等)
var claims = new[]
{
new Claim(ClaimTypes.Name, request.UserName),
new Claim(ClaimTypes.Role, "Admin"), // 角色(用于权限控制)
new Claim("UserId", "1001") // 自定义字段
};
// 3. 生成签名密钥
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
// 4. 创建 JWT Token
var token = new JwtSecurityToken(
issuer: _jwtSettings.Issuer,
audience: _jwtSettings.Audience,
claims: claims,
expires: DateTime.Now.AddMinutes(_jwtSettings.ExpireMinutes),
signingCredentials: creds
);
// 5. 返回 Token 字符串
var tokenStr = new JwtSecurityTokenHandler().WriteToken(token);
return Ok(new
{
Token = tokenStr,
ExpireTime = _jwtSettings.ExpireMinutes
});
}
}
}
5. 测试授权接口
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using JwtDemo.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authorization;
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
/// <summary>
/// 无需授权:公开接口
/// </summary>
[HttpGet("public")]
public IActionResult Public()
{
return Ok("这是公开接口,任何人可访问");
}
/// <summary>
/// 需要授权:私有接口
/// </summary>
[HttpGet("private")]
[Authorize] // 核心:添加此特性表示需要登录授权
public IActionResult Private()
{
// 获取当前登录用户信息
var userName = User.Identity?.Name;
return Ok($"这是私有接口,已授权!当前用户:{userName}");
}
/// <summary>
/// 角色授权:仅 Admin 可访问
/// </summary>
[HttpGet("admin")]
[Authorize(Roles = "Admin")]
public IActionResult AdminOnly()
{
return Ok("管理员专属接口");
}
}
四、测试流程(Postman/Swagger)
- 运行项目 → 打开 Swagger
- 调用
api/Account/login,传入账号密码:{ "userName": "admin", "password": "123456" } - 复制返回的 Token
- 调用
api/Test/private:- 请求头添加:
Authorization: Bearer 你的Token - 携带 Token → 访问成功
- 不携带 Token → 返回 401 未授权
- 请求头添加:
五、关键知识点
- [Authorize]:标记需要授权的接口/控制器
- [AllowAnonymous]:标记公开接口(跳过授权)
- Claim:存储用户信息(用户ID、角色、权限),可自定义
- 无状态:Token 存储所有用户信息,服务器无需保存会话
- 安全性:密钥必须保密,Token 过期时间不宜过长
六、常见问题
- 401 未授权
- 未携带
Authorization请求头 - Token 过期/错误
- 密钥、签发者配置不匹配
- 未携带
- Token 被篡改
- 服务器会自动验证签名,篡改后直接失效
- 跨域问题
- 前端调用需配置 CORS 跨域
总结
- 安装 JWT 包 → 配置 JWT 参数 → 注册认证服务
- 登录验证 → 生成 JWT Token 返回前端
- 接口添加
[Authorize]→ 实现授权验证 - 支持角色权限、自定义声明、无状态认证