You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

将应用从.NET Core 2.2升级至3.1后出现JwtSecurityToken过期时间无效引发401未授权错误

解决.NET Core 3.1升级后JWT令牌未过期却返回401的问题

我一眼就揪出了问题的核心——你在生成JWT令牌时,把nbf(生效时间)和exp(过期时间)这两个关键声明存成了字符串类型,而.NET Core 3.1的JWT验证器比2.2版本更严格遵循JWT标准,要求这两个声明必须是数值类型(NumericDate,即Unix时间戳整数),所以验证时直接判定令牌无效,返回401。

问题根源代码

看你生成令牌的这段代码:

Claim claimEffDate = new Claim(JwtRegisteredClaimNames.Nbf, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString());
lc.Add(claimEffDate);
Claim claimExpDate = new Claim(JwtRegisteredClaimNames.Exp, new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString());
lc.Add(claimExpDate);

这里你把ToUnixTimeSeconds()返回的整数转成了字符串存入Claim,而JWT标准明确要求nbfexp是数字格式,.NET Core 3.1的验证逻辑不再自动兼容字符串格式的数值声明。

两种修复方案

方案1:直接使用数值类型的Claim

去掉字符串转换,明确指定Claim的数值类型:

// 不转字符串,直接传入整数并指定类型为Integer64
Claim claimEffDate = new Claim(JwtRegisteredClaimNames.Nbf, 
    new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture), 
    ClaimValueTypes.Integer64);
lc.Add(claimEffDate);

Claim claimExpDate = new Claim(JwtRegisteredClaimNames.Exp, 
    new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture), 
    ClaimValueTypes.Integer64);
lc.Add(claimExpDate);

通过ClaimValueTypes.Integer64确保声明被验证器正确识别为数值类型。

方案2:使用JwtPayload属性直接设置(更推荐)

直接通过JwtPayload的内置属性设置生效和过期时间,无需手动添加Claim,更不易出错:

// 替换原有的JwtPayload构造逻辑
var payload = new JwtPayload
{
    { ClaimTypes.Name, sportapikey.Client }
};
// 直接设置生效和过期时间
payload.NotBefore = new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds();
payload.Expires = new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds();

// 添加其他自定义声明
foreach (string team in sportapikey.Teams)
{
    payload.Add(ClaimTypes.System, team.Trim());
}
foreach (string sport in sportapikey.Sports.Split(","))
{
    payload.Add(ClaimTypes.Role, sport.Trim());
}

// 生成令牌
token = new JwtSecurityToken(
    new JwtHeader(new SigningCredentials(
        new SymmetricSecurityKey(Encoding.UTF8.GetBytes("AnythingYouWant")),
        SecurityAlgorithms.HmacSha256)),
    payload);

验证修复效果

修复后重新生成令牌,用jwt.io解码查看nbfexp字段,它们应该显示为无引号的数字而非字符串,此时再用Postman测试接口,401未授权错误应该就会消失。

另外提个小建议:你在Startup里的UseCors()最好配置具体的跨域规则,默认允许所有的设置在生产环境存在安全风险。

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

火山引擎 最新活动