Files
step3/api/QuestionsApi/Services/TokenServices.cs
T

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();
}