You need to enable JavaScript to run this app. ASP.NET Core使用JWT认证始终返回401 HTTP错误问题求助
优惠活动
大模型
产品
解决方案
定价
更多

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逻辑:

  1. 去掉ProfileController上[Authorize]特性指定的AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme参数。
  2. 替换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);
}
  1. 可以移除Startup中配置的JWT相关服务,保持Identity默认配置即可。

方案2:坚持使用JWT认证的适配方法

如果必须使用JWT,需要调整配置让JWT能从网页请求的Cookie中读取凭证:

  1. 调整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;
        }
    };
});
  1. 调整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" });
}
  1. 生成token时把DateTime.Now改成DateTime.UtcNow,避免时区问题。

内容的提问来源于stack exchange,提问作者Ali Sultan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.08 11:48:03