52 lines
2.2 KiB
C#
52 lines
2.2 KiB
C#
using Microsoft.IdentityModel.Tokens;
|
|
using MongoDB.Driver;
|
|
using QuestionsApi.Models;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Security.Claims;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
namespace QuestionsApi.Services;
|
|
|
|
public sealed class TokenBlacklistStore(MongoDatabaseProvider mongo)
|
|
{
|
|
private readonly IMongoCollection<BlacklistedToken> _tokens =
|
|
mongo.Database.GetCollection<BlacklistedToken>("BlacklistedTokens");
|
|
|
|
public Task AddAsync(string jti, DateTime expiresAt) =>
|
|
_tokens.ReplaceOneAsync(token => token.Jti == jti,
|
|
new BlacklistedToken { Jti = jti, ExpiresAt = expiresAt },
|
|
new ReplaceOptions { IsUpsert = true });
|
|
|
|
public Task<bool> ContainsAsync(string jti) => _tokens.Find(token => token.Jti == jti).AnyAsync();
|
|
internal IMongoCollection<BlacklistedToken> Collection => _tokens;
|
|
}
|
|
|
|
public sealed class JwtTokenService(IConfiguration configuration)
|
|
{
|
|
public (string Token, string Jti, DateTime ExpiresUtc) Generate(AuthUser user)
|
|
{
|
|
var key = Encoding.UTF8.GetBytes(configuration["Jwt:Key"]
|
|
?? throw new InvalidOperationException("Jwt:Key missing"));
|
|
var issuer = configuration["Jwt:Issuer"] ?? "promiscuity";
|
|
var audience = configuration["Jwt:Audience"] ?? issuer;
|
|
var credentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256);
|
|
var jti = Guid.NewGuid().ToString("N");
|
|
var expiresUtc = DateTime.UtcNow.AddMinutes(15);
|
|
var claims = new[]
|
|
{
|
|
new Claim(ClaimTypes.Name, user.Username),
|
|
new Claim(ClaimTypes.NameIdentifier, user.Id),
|
|
new Claim(ClaimTypes.Role, user.Role),
|
|
new Claim(JwtRegisteredClaimNames.Jti, jti),
|
|
new Claim("auth_ver", user.AuthVersion.ToString(System.Globalization.CultureInfo.InvariantCulture))
|
|
};
|
|
var token = new JwtSecurityToken(issuer, audience, claims, expires: expiresUtc,
|
|
signingCredentials: credentials);
|
|
return (new JwtSecurityTokenHandler().WriteToken(token), jti, expiresUtc);
|
|
}
|
|
|
|
public static string NewRefreshToken() =>
|
|
Convert.ToHexString(RandomNumberGenerator.GetBytes(32)).ToLowerInvariant();
|
|
}
|