JwtSecurityToken 到期时间无效.NET Core 3.1
JwtSecurityToken Expiry Time Invalid .NET Core 3.1
我将我的应用程序从 .NET Core 2.2 升级到 .NET Core 3.1。当我尝试使用 PostMan 测试我的端点时,我注意到我遇到了 401 Unauth 错误。当我查看 header 时,我发现到期时间无效:
我使用了以下不记名令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiQm9iIiwibmJmIjoiMTYxNzk3Nzg1MSIsImV4cCI6IjE2MjMxNjE4NTYiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiQmFza2V0YmFsbCIsIlJ1Z2J5IiwiRm9vdGJhbGwiXX0.QRLuXFeopf7QZ1NUzWcctuSfnNXiPgc2UH7NxAuHYvw
我正在获取我的生成令牌端点并使用 jwt.io 对其进行解码,exp 字段为“1623161856”。
我将其转换为 Javascript 中的日期 object,它等于未来 60 天。
所以令牌肯定没有过期。不确定在升级到 .NET Core 3.1 时是否遗漏了任何内容,但这里是相关代码:
在Startup.cs
我有
public void ConfigureServices(IServiceCollection services)
{
// Initial Setup
services.AddMvc();
services.AddSingleton<IConfiguration>(Configuration);
// Call this in case you need aspnet-user-authtype/aspnet-user-identity
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(Configuration["v1"], new OpenApiInfo { Title = Configuration["Sports"], Version = Configuration["v1] });
});
services.AddDataProtection();
//Authentication Setup
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("AnythingYouWant")),
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5)
};
options.SaveToken = true;
options.Events = new JwtBearerEvents()
{
OnTokenValidated = context =>
{
var accessToken = context.SecurityToken as JwtSecurityToken;
if (accessToken != null)
{
ClaimsIdentity identity = context.Principal.Identity as ClaimsIdentity;
if (identity != null)
{
identity.AddClaim(new Claim("access_token", accessToken.RawData));
}
}
return Task.CompletedTask;
}
};
});
services.AddAuthorization();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/" + Configuration["v1"] + "/swagger.json", Configuration["Sports"]);
});
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("swagger", "swagger/");
});
app.UseWelcomePage("/swagger");
}
令牌由我的 api 端点之一生成。该代码如图所示:
[HttpPost("SportApi/Token")]
[ServiceFilter(typeof(SportResourceFilter))]
public IActionResult Create(string key)
{
return new ObjectResult(GenerateToken(key));
}
private string GenerateToken(string someKey)
{
JwtSecurityToken token = new JwtSecurityToken();
List<SportAPIKey> ro = new List<SportAPIKey>();
if (!string.IsNullOrEmpty(someKey))
{
using (StreamReader r = new StreamReader("keys.json"))
{
string json = r.ReadToEnd();
ro = JsonConvert.DeserializeObject<List<SportAPIKey>>(json);
}
if (ro.Exists(sak => sak.SportAPIKeyValue.Equals(someKey)))
{
SportAPIKey sportapikey = ro.Find(sak => sak.SportAPIKeyValue.Equals(someKey));
List<Claim> lc = new List<Claim>();
Claim claimClient = new Claim(ClaimTypes.Name, sportapikey.Client);
lc.Add(claimClient);
foreach (string team in sportapikey.Teams)
{
lc.Add(new Claim(ClaimTypes.System, team.Trim()));
}
Claim claimEffDate = new Claim(JwtRegisteredClaimNames.Nbf, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString());
lc.Add(claimEffDate);
int tokenLifespan = 60;
Claim claimExpDate = new Claim(JwtRegisteredClaimNames.Exp, new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString());
lc.Add(claimExpDate);
foreach (string sport in sportapikey.Sports.Split(","))
{
lc.Add(new Claim(ClaimTypes.Role, sport.Trim()));
}
var claims = lc.ToArray();
token = new JwtSecurityToken(
new JwtHeader(new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes("AnythingYouWant")),
SecurityAlgorithms.HmacSha256)),
new JwtPayload(claims));
}
}
return new JwtSecurityTokenHandler().WriteToken(token);
}
您的令牌包含时间戳 nbf
和 exp
作为字符串:
"nbf": "1617977851",
"exp": "1623161856",
这是无效的。在 https:\jwt.io 上,当您将鼠标悬停在这些值上时,您会发现出现了问题。通常它显示时间戳,但在您的示例中它显示:“无效日期”:
JWT 中的时间戳应该是 numerical values:
NumericDate
A JSON numeric value representing the number of seconds from
1970-01-01T00:00:00Z UTC until the specified UTC date/time
值本身是正确的:
生成声明期间发生错误:
Claim claimExpDate = new Claim(JwtRegisteredClaimNames.Exp,
new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString());
lc.Add(claimExpDate);
改为使用this constructor, which lets you set the ClaimValueType:
new Claim(JwtRegisteredClaimNames.Exp,
new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString(),
ClaimValueTypes.Integer64)
或者更好的是,让框架为您添加过期时间戳,使用 this constructor:
public JwtSecurityToken (string issuer = default, string audience = default, System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> claims = default, DateTime? notBefore = default, DateTime? expires = default, Microsoft.IdentityModel.Tokens.SigningCredentials signingCredentials = default);
例如:
JwtSecurityToken(expires: DateTime.UtcNow.AddDays(60), ...)
我将我的应用程序从 .NET Core 2.2 升级到 .NET Core 3.1。当我尝试使用 PostMan 测试我的端点时,我注意到我遇到了 401 Unauth 错误。当我查看 header 时,我发现到期时间无效:
我使用了以下不记名令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiQm9iIiwibmJmIjoiMTYxNzk3Nzg1MSIsImV4cCI6IjE2MjMxNjE4NTYiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiQmFza2V0YmFsbCIsIlJ1Z2J5IiwiRm9vdGJhbGwiXX0.QRLuXFeopf7QZ1NUzWcctuSfnNXiPgc2UH7NxAuHYvw
我正在获取我的生成令牌端点并使用 jwt.io 对其进行解码,exp 字段为“1623161856”。
所以令牌肯定没有过期。不确定在升级到 .NET Core 3.1 时是否遗漏了任何内容,但这里是相关代码:
在Startup.cs
我有
public void ConfigureServices(IServiceCollection services)
{
// Initial Setup
services.AddMvc();
services.AddSingleton<IConfiguration>(Configuration);
// Call this in case you need aspnet-user-authtype/aspnet-user-identity
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(Configuration["v1"], new OpenApiInfo { Title = Configuration["Sports"], Version = Configuration["v1] });
});
services.AddDataProtection();
//Authentication Setup
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("AnythingYouWant")),
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5)
};
options.SaveToken = true;
options.Events = new JwtBearerEvents()
{
OnTokenValidated = context =>
{
var accessToken = context.SecurityToken as JwtSecurityToken;
if (accessToken != null)
{
ClaimsIdentity identity = context.Principal.Identity as ClaimsIdentity;
if (identity != null)
{
identity.AddClaim(new Claim("access_token", accessToken.RawData));
}
}
return Task.CompletedTask;
}
};
});
services.AddAuthorization();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/" + Configuration["v1"] + "/swagger.json", Configuration["Sports"]);
});
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("swagger", "swagger/");
});
app.UseWelcomePage("/swagger");
}
令牌由我的 api 端点之一生成。该代码如图所示:
[HttpPost("SportApi/Token")]
[ServiceFilter(typeof(SportResourceFilter))]
public IActionResult Create(string key)
{
return new ObjectResult(GenerateToken(key));
}
private string GenerateToken(string someKey)
{
JwtSecurityToken token = new JwtSecurityToken();
List<SportAPIKey> ro = new List<SportAPIKey>();
if (!string.IsNullOrEmpty(someKey))
{
using (StreamReader r = new StreamReader("keys.json"))
{
string json = r.ReadToEnd();
ro = JsonConvert.DeserializeObject<List<SportAPIKey>>(json);
}
if (ro.Exists(sak => sak.SportAPIKeyValue.Equals(someKey)))
{
SportAPIKey sportapikey = ro.Find(sak => sak.SportAPIKeyValue.Equals(someKey));
List<Claim> lc = new List<Claim>();
Claim claimClient = new Claim(ClaimTypes.Name, sportapikey.Client);
lc.Add(claimClient);
foreach (string team in sportapikey.Teams)
{
lc.Add(new Claim(ClaimTypes.System, team.Trim()));
}
Claim claimEffDate = new Claim(JwtRegisteredClaimNames.Nbf, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString());
lc.Add(claimEffDate);
int tokenLifespan = 60;
Claim claimExpDate = new Claim(JwtRegisteredClaimNames.Exp, new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString());
lc.Add(claimExpDate);
foreach (string sport in sportapikey.Sports.Split(","))
{
lc.Add(new Claim(ClaimTypes.Role, sport.Trim()));
}
var claims = lc.ToArray();
token = new JwtSecurityToken(
new JwtHeader(new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes("AnythingYouWant")),
SecurityAlgorithms.HmacSha256)),
new JwtPayload(claims));
}
}
return new JwtSecurityTokenHandler().WriteToken(token);
}
您的令牌包含时间戳 nbf
和 exp
作为字符串:
"nbf": "1617977851",
"exp": "1623161856",
这是无效的。在 https:\jwt.io 上,当您将鼠标悬停在这些值上时,您会发现出现了问题。通常它显示时间戳,但在您的示例中它显示:“无效日期”:
JWT 中的时间戳应该是 numerical values:
NumericDate
A JSON numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time
值本身是正确的:
生成声明期间发生错误:
Claim claimExpDate = new Claim(JwtRegisteredClaimNames.Exp,
new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString());
lc.Add(claimExpDate);
改为使用this constructor, which lets you set the ClaimValueType:
new Claim(JwtRegisteredClaimNames.Exp,
new DateTimeOffset(DateTime.Now.AddDays(tokenLifespan)).ToUnixTimeSeconds().ToString(),
ClaimValueTypes.Integer64)
或者更好的是,让框架为您添加过期时间戳,使用 this constructor:
public JwtSecurityToken (string issuer = default, string audience = default, System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> claims = default, DateTime? notBefore = default, DateTime? expires = default, Microsoft.IdentityModel.Tokens.SigningCredentials signingCredentials = default);
例如:
JwtSecurityToken(expires: DateTime.UtcNow.AddDays(60), ...)