jwt验签失败主因是算法不匹配或密钥未对齐;需确认validateissuersigningkey为true、密钥长度合规、token未被url编码污染,并用jwt.io比对签名。

JWT签名验证失败:SecurityTokenInvalidSignatureException 怎么快速定位
多数 JWT 认证卡在验签环节,不是算法配错就是密钥没对齐。C# 默认用 Microsoft.IdentityModel.Tokens 验证,但常见错误是服务端用 HmacSha256 签名,客户端却按 RsaSha256 解析,或者密钥字符串前后多空格、换行。
- 检查
TokenValidationParameters.ValidateIssuerSigningKey必须设为true,否则跳过签名验证 -
IssuerSigningKey要用new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-32-byte-secret")),长度不够会静默失败(比如只传了16字节) - 确认前端传来的
Authorization: Bearer xxx中的 token 没被 URL 编码污染(比如+变成空格),建议用Uri.UnescapeDataString预处理 - 错误信息里出现
IDX10501: Signature validation failed时,先打印原始 token 的 header.payload 部分,用 jwt.io 手动比对签名是否一致
.NET 6+ 中间件配置:为什么 AddJwtBearer 后接口还是 401
加了中间件不代表自动生效,顺序和条件漏一个就白配。最常踩的坑是中间件注册位置不对,或没启用认证服务。
-
services.AddAuthentication().AddJwtBearer()必须在AddControllers之前调用 -
app.UseAuthentication()必须在app.UseAuthorization()之前,且不能放在UseStaticFiles后面(否则静态资源拦截器可能提前返回) - 控制器方法上必须显式加
[Authorize],[AllowAnonymous] 是例外,不加默认不校验 - 如果用
MapControllers,确保没漏掉app.UseRouting()—— 缺它会导致认证上下文为空
自定义 OnTokenValidated 里怎么安全获取用户角色
JWT payload 里的 role 字段默认不会自动映射到 User.IsInRole(),得手动注入 ClaimsPrincipal。直接改 context.Principal 是可行的,但要注意线程安全和 Claim 重复添加。
- 别在
OnTokenValidated里查数据库同步加载角色(会阻塞请求),应提前把角色写进 token 的rolesclaim,或用OnUserInformationReceived异步补充 - 添加 role claim 时用
new Claim(ClaimTypes.Role, "admin"),不要用自定义字符串键名,否则IsInRole("admin")不识别 - 如果 token 里是数组型
"roles": ["user", "editor"],需手动遍历解析并逐个 Add,.NET 不自动展开 JSON 数组
刷新 Token 的安全实践:为什么不能只靠 Expires
单纯延长 exp 时间等于放弃时效控制,真正的刷新需要独立的 refresh token 机制,且必须绑定设备/IP/指纹等上下文。
- access token 保持短时效(如 15 分钟),refresh token 单独生成、加密存储、带
use声明和唯一 jti,且每次使用后立即失效 - 别把 refresh token 放在 localStorage —— XSS 可直接盗取;应存在 httpOnly cookie,并设
SameSite=Strict - 验证 refresh token 时,必须检查它是否与当前 access token 的
sub和iss匹配,防止跨账号重放 - ASP.NET Core 没内置 refresh 流程,得自己实现 endpoint,别依赖
Microsoft.AspNetCore.Authentication.JwtBearer自动处理
JWT 本身不解决登出问题,黑名单或短生命周期是唯二靠谱手段;别信“服务端删 token”这种说法——token 已签发,删的是记录,不是凭证。










