一、生成token
public string CreateToken(UserDto input)
{
var tokenHandler = new JwtSecurityTokenHandler();
var authTime = DateTime.Now;
var expiresAt = authTime.AddHours(_myOptions.AccessTokenTime);//到期时间
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(JwtClaimTypes.Audience,"api"),
new Claim(JwtClaimTypes.Issuer,"KouBei"),
new Claim(JwtClaimTypes.Id, input.Id),
new Claim(JwtClaimTypes.PhoneNumber, input.Phone),
new Claim(JwtClaimTypes.NotBefore, $"{new DateTimeOffset(authTime).ToUnixTimeSeconds()}"),//token生效时间
new Claim(JwtClaimTypes.Expiration, $"{new DateTimeOffset(expiresAt).ToUnixTimeSeconds()}")//到期时间,按秒数计算
}),
IssuedAt = DateTime.Now,//token生成时间
Expires = expiresAt,
NotBefore = authTime,
SigningCredentials = new SigningCredentials(symmetricKey, SecurityAlgorithms.HmacSha256Signature)//密钥和加密方式
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
return tokenString;
}
二、Startup
配置
ConfigureServices
方法中:
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
o.Events = new JwtBearerEvents()
{
OnMessageReceived = context =>
{
context.Token = context.Request.Query["AccessToken"];
return Task.CompletedTask;
}
};
o.SaveToken = true;
o.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role,
ValidIssuer = "KouBei",
ValidAudience = "api",
IssuerSigningKey = symmetricKey,
// 是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
ValidateLifetime = true,
//注意这是缓冲过期时间,总的有效时间等于这个时间加上jwt的过期时间,如果不配置,默认是5分钟
ClockSkew = TimeSpan.FromSeconds(4)
};
});
c# - .NetCore JwtBearerAuthentication
不拒绝过期的 token
我正在生成 JWT 以用于我的 WebApi 项目。我将 token
设置为在一分钟内过期,以便我可以测试它在过期日期之后提交时是否拒绝 token
。
CreateToken Controller
public async Task<IActionResult> CreateToken([FromBody] CredentialModel model)
{
var user = await _unitOfWork.UserManager.FindByNameAsync(model.UserName);
if (user == null) return BadRequest();
if (Hasher.VerifyHashedPassword(user, user.PasswordHash, model.Password) != PasswordVerificationResult.Success) return BadRequest();
var userClaims = await UserManager.GetClaimsAsync(user);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString()),
new Claim(JwtRegisteredClaimNames.GivenName, user.FirstName),
new Claim(JwtRegisteredClaimNames.FamilyName, user.LastName),
new Claim(JwtRegisteredClaimNames.Email, user.Email)
}
.Union(userClaims);
var cert = new Certificate(Configuration["Tokens:Certificate"]);
var token = new JwtSecurityToken(
issuer: Configuration["Tokens:Issuer"],
audience: Configuration["Tokens:Audience"],
claims: claims,
expires: DateTime.UtcNow.AddMinutes(1),
signingCredentials: cert.Signature
);
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
expiration = token.ValidTo
});
}
token
认证-启动类
app.UseJwtBearerAuthentication(new JwtBearerOptions()
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = Configuration["Tokens:Issuer"],
ValidAudience = Configuration["Tokens:Audience"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new Certificate(Configuration["Tokens:Certificate"]).SecurityKey,
ValidateLifetime = true
},
});
尽管我设置了 validateLifetime = true
,但两分钟后 token
不会被拒绝。它将继续接受 token
。是否有我不知道的最短到期时间或我的设置错误?
ClockSkew
的默认值为 5 分钟。
app.UseJwtBearerAuthentication(new JwtBearerOptions()
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = Configuration["Tokens:Issuer"],
ValidAudience = Configuration["Tokens:Audience"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new Certificate(certPath: Configuration["Tokens:Certificate"], isValid: false).SecurityKey,
ValidateLifetime = true,
ValidateIssuer = true,
ValidateAudience = true,
ClockSkew = TimeSpan.Zero
},
});