ASP.NET Core使用JWT认证始终返回401 HTTP错误问题求助
问题根因
- 核心问题:生成JWT后未将凭证传递到后续跳转请求。JWT默认从HTTP请求的
Authorization请求头读取Bearer {token}格式的凭证,你登录生成token后直接调用RedirectToAction执行服务端重定向,新的跳转请求没有携带JWT凭证,自然触发401未授权错误。 - 配置冲突:项目同时引入了ASP.NET Core Identity(默认采用Cookie认证)和JWT认证,且将全局默认认证方案设置为JWT,但你的使用场景是服务端渲染的网页跳转,JWT本身更适配前后端分离的API场景,和传统网页跳转的交互逻辑不适配。
- 配置逻辑矛盾:JWT校验配置中同时开启了
ValidateLifetime = true和RequireExpirationTime = false,逻辑冲突,且生成token时使用本地时间DateTime.Now,容易因时区差异导致token被判定为未生效/已过期。 - 参数校验不匹配:生成JWT时传入了issuer和audience参数,但校验配置中关闭了
ValidateIssuer和ValidateAudience,虽然当前不会触发问题,但后续开启校验时容易出现参数不匹配的401错误。
解决方案
方案1:适配传统网页场景,直接使用Identity自带的Cookie认证(推荐)
你的场景是服务端渲染的网页应用,直接用Identity默认的Cookie认证即可,不需要自己实现JWT逻辑:
- 去掉
ProfileController上[Authorize]特性指定的AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme参数。 - 替换Account控制器的登录逻辑,直接调用Identity自带的登录方法:
[HttpPost, ValidateAntiForgeryToken] public async Task<IActionResult> Login(LoginVM model) { var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, isPersistent: false, lockoutOnFailure: false); if (result.Succeeded) { return RedirectToAction("Index", "Profile", new { area = "Store" }); } ModelState.AddModelError("", (string)_localizer["InvalidLogin"]); return View(model); }
- 可以移除Startup中配置的JWT相关服务,保持Identity默认配置即可。
方案2:坚持使用JWT认证的适配方法
如果必须使用JWT,需要调整配置让JWT能从网页请求的Cookie中读取凭证:
- 调整Startup中JWT的配置,添加从Cookie读取token的逻辑:
.AddJwtBearer(jwt => { var key = Encoding.ASCII.GetBytes(_configuration["JWT:key"]); jwt.SaveToken = true; jwt.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false, RequireExpirationTime = true, ValidateLifetime = true, ClockSkew = TimeSpan.Zero // 取消token过期时间的宽容期 }; // 新增:从Cookie读取JWT token jwt.Events = new JwtBearerEvents { OnMessageReceived = context => { context.Token = context.Request.Cookies["access_token"]; return Task.CompletedTask; } }; });
- 调整Account控制器的登录逻辑,生成token后写入Cookie:
var token = new JwtSecurityTokenHandler().WriteToken(JWTtoken); if (token != null) { // 把token写入HttpOnly Cookie,避免前端XSS攻击窃取 Response.Cookies.Append("access_token", token, new CookieOptions { HttpOnly = true, Expires = DateTimeOffset.UtcNow.AddMinutes(90), Secure = true // 生产环境HTTPS下建议开启 }); return RedirectToAction("Index", "Profile", new { area = "Store" }); }
- 生成token时把
DateTime.Now改成DateTime.UtcNow,避免时区问题。
内容的提问来源于stack exchange,提问作者Ali Sultan
相关产品推荐
相关产品推荐

