using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.Extensions.Caching.Distributed; namespace Infrastructure.Extensions; public sealed class DistributedCacheTicketStore : ITicketStore { private readonly IDistributedCache _cache; private readonly TicketSerializer _serializer = TicketSerializer.Default; private readonly string _keyPrefix; public DistributedCacheTicketStore(IDistributedCache cache, string keyPrefix = "AuthTicket:") { _cache = cache; _keyPrefix = keyPrefix; } private string BuildKey(string key) => _keyPrefix + key; private static DistributedCacheEntryOptions BuildEntryOptions(AuthenticationTicket ticket) { // CookieAuthenticationHandler usually sets ExpiresUtc. var expires = ticket.Properties.ExpiresUtc; if (expires.HasValue) { return new DistributedCacheEntryOptions { AbsoluteExpiration = expires.Value }; } // Fallback if ExpiresUtc is null. return new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(8) }; } public async Task StoreAsync(AuthenticationTicket ticket) { var key = Guid.NewGuid().ToString("N"); await RenewAsync(key, ticket); return key; } public async Task RenewAsync(string key, AuthenticationTicket ticket) { var data = _serializer.Serialize(ticket); var options = BuildEntryOptions(ticket); await _cache.SetAsync(BuildKey(key), data, options); } public async Task RetrieveAsync(string key) { var data = await _cache.GetAsync(BuildKey(key)); return data is null ? null : _serializer.Deserialize(data); } public Task RemoveAsync(string key) => _cache.RemoveAsync(BuildKey(key)); }