我遇到了使用webapi生成的令牌(jwt)的问题。当它为用户生成令牌时,它会正常访问系统,但是当它再次请求访问系统并生成新令牌时,它会说当我进行任何调用时新生成的令牌无效。
我正在使用webapi asp.net核心。
private Customer _customer;
private readonly ICustomerRepository _repository;
private readonly TokenOptions _tokenOptions;
private readonly JsonSerializerSettings _serializerSettings;
public AccountController(IOptions<TokenOptions> jwtOptions, IUow uow, ICustomerRepository repository) : base(uow)
{
_repository = repository;
_tokenOptions = jwtOptions.Value;
ThrowIfInvalidOptions(_tokenOptions);
_serializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
}
[HttpPost]
[AllowAnonymous]
[Route("v1/authenticate")]
public async Task<IActionResult> Post([FromForm] AuthenticateUserCommand command)
{
if (command == null)
return await Response(null, new List<Notification> { new Notification("User", "Usuário ou senha inválidos") });
var identity = await GetClaims(command);
if (identity == null)
return await Response(null, new List<Notification> { new Notification("User", "Usuário ou senha inválidos") });
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.UniqueName, command.Username),
new Claim(JwtRegisteredClaimNames.Jti, await _tokenOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_tokenOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst("ModernStore")
};
var jwt = new JwtSecurityToken(
issuer: _tokenOptions.Issuer,
audience: _tokenOptions.Audience,
claims: claims.AsEnumerable(),
notBefore: _tokenOptions.NotBefore,
expires: _tokenOptions.Expiration,
signingCredentials: _tokenOptions.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
var response = new
{
token = encodedJwt,
expires = (int)_tokenOptions.ValidFor.TotalSeconds,
user = new
{
id = _customer.Id,
email = _customer.Email.Address,
username = _customer.User.Username
}
};
var json = JsonConvert.SerializeObject(response, _serializerSettings);
return new OkObjectResult(json);
}
private static void ThrowIfInvalidOptions(TokenOptions options)
{
if (options == null) throw new ArgumentNullException(nameof(options));
if (options.ValidFor <= TimeSpan.Zero)
throw new ArgumentException("O período deve ser maior que zero", nameof(TokenOptions.ValidFor));
if (options.SigningCredentials == null)
throw new ArgumentNullException(nameof(TokenOptions.SigningCredentials));
if (options.JtiGenerator == null)
throw new ArgumentNullException(nameof(TokenOptions.JtiGenerator));
}
private static long ToUnixEpochDate(DateTime date)
=> (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);
private Task<ClaimsIdentity> GetClaims(AuthenticateUserCommand command)
{
var customer = _repository.GetByUsername(command.Username);
if (customer == null)
return Task.FromResult<ClaimsIdentity>(null);
if (!customer.User.Authenticate(command.Username, command.Password))
return Task.FromResult<ClaimsIdentity>(null);
_customer = customer;
return Task.FromResult(new ClaimsIdentity(
new GenericIdentity(customer.User.Username, "Token"),
new[] {
new Claim("ModernStore", "User")
}));
}
}