在前后端分离成为主流的今天,传统的 Session/Cookie 认证已经力不从心 —— 跨域、分布式、移动端适配全是痛点。而JWT(JSON Web Token) 就是解决这些问题的「万能钥匙」!
今天这篇专栏,我会手把手带你完成ASP.NET Core JWT 认证完整配置,从 Nuget 引用、代码编写到高频踩坑全解析,用生活类比让你秒懂,新手也能直接 CV 跑通!
一、先搞懂:JWT 是什么?(生活类比 + 核心流程)
1. 生活类比:JWT = 景区电子门票
- 传统 Session:你去景区买票,工作人员把你的信息记在本子上,你只拿一个编号,每次进门都要查本子(服务器存储状态);
- JWT 认证:景区给你一张加密电子票,上面写着你的身份、有效期、权限,票自己拿着,进门时工作人员扫码验证(票里自带信息,服务器不存储)。
2. JWT 核心认证流程图
3. 核心价值
1.无状态:服务器不存储用户信息,分布式部署无压力;
2.跨域支持:完美适配前后端分离、小程序、APP;
3.安全可控:加密签名、过期时间、权限声明全自定义。
二、第一步:项目配置与 Nuget 包引用
1. 环境要求
- 框架:ASP.NET Core 6/7/8(本文以.NET 6 为例)
- 核心包:Microsoft.AspNetCore.Authentication.JwtBearer(官方 JWT 认证中间件)
2. 安装 Nuget 包(两种方式)
方式 1:Nuget 包管理器
VS 中右键项目 → 管理 Nuget 程序包 → 浏览 → 搜索**Microsoft.AspNetCore.Authentication.JwtBearer ** → 安装最新稳定版。
方式 2:程序包管理器控制台
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
方式 3:.NET CLI 命令
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
三、第二步:appsettings.json 配置 JWT 核心参数
我们把 JWT 的密钥、颁发者、过期时间等配置写在配置文件,方便后期修改。
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"JwtSettings": {
"SecretKey": "LongLongSecretKey@1234567890ABCDEF",
"Issuer": "MyBackendServer",
"Audience": "MyFrontendClient",
"ExpiresMinutes": 60
},
"AllowedHosts": "*"
}
✅ 小节重点
- SecretKey:绝对不能泄露!相当于你的令牌「签名钥匙」,泄露后任何人都能伪造令牌;
- ExpiresMinutes:不建议设置过长,建议 30~120 分钟,配合刷新 Token 使用;
3.Issuer 和 Audience:前后端必须保持一致,否则验证失败。
四、第三步:Program.cs 注册 JWT 认证服务(核心代码)
这是 JWT 生效的核心步骤,我们需要在 Program.cs 中注册认证、授权服务,并启用中间件。
完整代码(.NET 6+ 顶级语句)
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var jwtSettings = builder.Configuration.GetSection("JwtSettings");
var secretKey = jwtSettings["SecretKey"];
var issuer = jwtSettings["Issuer"];
var audience = jwtSettings["Audience"];
var expiresMinutes = Convert.ToDouble(jwtSettings["ExpiresMinutes"]);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = issuer,
ValidateAudience = true,
ValidAudience = audience,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)),
ClockSkew = TimeSpan.Zero
};
options.Events = new JwtBearerEvents
{
OnChallenge = context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
context.Response.ContentType = "application/json";
var result = new { code = 401, message = "未授权:请先登录获取Token" };
context.Response.WriteAsync(System.Text.Json.JsonSerializer.Serialize(result));
return Task.CompletedTask;
}
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
✅ 小节重点
- 中间件顺序:UseAuthentication 必须在 UseAuthorization 之前!先认证身份,再判断权限;
- ClockSkew:设置为 0,严格校验过期时间,避免令牌超时仍能使用;
- 自定义 OnChallenge:让认证失败返回友好 JSON,而非默认的 HTML 页面。
五、第四步:编写 JWT 令牌生成工具类
我们封装一个通用工具类,用于用户登录成功后生成 JWT 令牌。
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace JwtDemo.Utils
{
public static class JwtTokenHelper
{
public static string CreateToken(IConfiguration configuration, string userId, string userName, string role)
{
var jwtSettings = configuration.GetSection("JwtSettings");
var secretKey = jwtSettings["SecretKey"];
var issuer = jwtSettings["Issuer"];
var audience = jwtSettings["Audience"];
var expiresMinutes = Convert.ToDouble(jwtSettings["ExpiresMinutes"]);
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, userId),
new Claim(ClaimTypes.Name, userName),
new Claim(ClaimTypes.Role, role),
new Claim("CustomInfo", "自定义业务数据")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: issuer,
audience: audience,
claims: claims,
expires: DateTime.Now.AddMinutes(expiresMinutes),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
}
✅ 小节重点
- Claim(声明):存储在令牌里的用户信息,相当于门票上的「身份信息」;
- 角色声明:用于后续权限控制,必须用ClaimTypes.Role类型;
- 令牌加密:固定使用HmacSha256算法,安全性最高。
六、第五步:编写登录接口 + 受保护接口
1. 登录接口(无需认证,生成 Token)
using Microsoft.AspNetCore.Mvc;
using JwtDemo.Utils;
namespace JwtDemo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LoginController : ControllerBase
{
private readonly IConfiguration _configuration;
public LoginController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpPost]
public IActionResult Login(string userName, string password)
{
if (userName == "admin" && password == "123456")
{
var token = JwtTokenHelper.CreateToken(_configuration, "1001", userName, "admin");
return Ok(new
{
code = 200,
message = "登录成功",
token = token,
expiresIn = 60
});
}
return Ok(new { code = 400, message = "账号或密码错误" });
}
}
}
2. 受保护接口(需要 JWT 认证才能访问)
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace JwtDemo.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class UserController : ControllerBase
{
[HttpGet("info")]
public IActionResult GetUserInfo()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var userName = User.Identity?.Name;
var role = User.FindFirst(ClaimTypes.Role)?.Value;
return Ok(new
{
code = 200,
message = "获取用户信息成功",
data = new { userId, userName, role }
});
}
[HttpGet("admin")]
[Authorize(Roles = "admin")]
public IActionResult AdminApi()
{
return Ok(new { code = 200, message = "管理员接口访问成功" });
}
}
}
✅ 小节重点
1.[AllowAnonymous]:跳过认证,登录接口必须加;
2.[Authorize]:需要认证才能访问;
3.[Authorize(Roles = “admin”)]:角色授权,仅指定角色可访问。
七、高频踩坑大全(90% 的新手都栽过!)
1. 中间件顺序错误(最常见)
- ❌ 错误:app.UseAuthorization() 在 app.UseAuthentication() 之前;
- ✅ 正确:先认证,后授权 ,顺序不可逆。
2. JWT 密钥太短 / 泄露
- ❌ 错误:密钥长度 < 16 位,或硬编码在代码中提交到 Git;
- ✅ 正确:密钥≥16 位,存配置文件,严格保密。
3. Issuer/Audience 前后端不一致
- ❌ 错误:后端配置Issuer=“A”,前端校验Issuer=“B”;
- ✅ 正确:前后端配置必须完全一致。
4. 令牌过期 / 服务器时间不同步
- ❌ 错误:未设置ClockSkew,导致令牌明明没过期却验证失败;
- ✅ 正确:设置ClockSkew = TimeSpan.Zero。
5. 前端请求头格式错误
- ❌ 错误:Authorization: Token xxxxx 或 直接写 Token;
- ✅ 正确:Authorization: Bearer 你的JWT令牌(Bearer + 空格 必须有)。
6. 忘记注册认证服务
- ❌ 错误:只写UseAuthentication,没写AddAuthentication;
- ✅ 正确:先注册服务,再启用中间件。
八、测试验证(Postman/Swagger)
1.运行项目,访问/api/Login,输入账号密码获取 Token;
2.访问/api/User/info,请求头添加Authorization: Bearer 你的Token;
3.验证结果:
- 携带有效 Token → 返回 200 + 用户信息;
- 无 Token / 无效 Token → 返回 401 未授权;
- 普通用户访问管理员接口 → 返回 403 禁止访问。
📢 结尾互动
今天的 JWT 认证全套配置就讲完啦!从代码 CV 到避坑,新手也能直接落地前后端分离项目!
互动问题
你在项目中用的是 JWT 还是 Session 认证?
你还遇到过哪些 JWT 踩坑问题?评论区告诉我!
总结
1.JWT = 前后端分离必备认证方案,无状态、跨域、安全;
2.核心三步:安装 Nuget 包→注册认证服务→生成 / 验证令牌;
3.避坑核心:中间件顺序、密钥安全、请求头格式三大关键点;
4.代码全量可直接 CV 运行,适合.NET6/7/8 所有版本!
转自https://blog.csdn.net/William_cl/article/details/159736029