using System; using System.Threading.Tasks; using gehGassi.Core.Interfaces; using gehGassi.Web.Helper; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace gehGassi.Web.Auth { /// /// Ticketstore für AuthenticationTickets /// public class MemoryCacheTicketStore : ITicketStore { private readonly IOptions _sessionSettings; private const string KeyPrefix = "AuthSessionStore-"; private IMemoryCache _cache; public MemoryCacheTicketStore(IOptions sessionSettings) { _sessionSettings = sessionSettings; _cache = new MemoryCache(new MemoryCacheOptions()); } public async Task ClearAll() { await Task.Delay(1); _cache.Dispose(); _cache = new MemoryCache(new MemoryCacheOptions()); } public async Task StoreAsync(AuthenticationTicket ticket) { var key = KeyPrefix + ticket.Principal.Identity.Name; await RenewAsync(key, ticket); return key; } public Task RenewAsync(string key, AuthenticationTicket ticket) { if (!key.StartsWith(KeyPrefix)) key = KeyPrefix + key; var options = new MemoryCacheEntryOptions(); var expiresUtc = ticket.Properties.ExpiresUtc; if (expiresUtc.HasValue) { options.SetAbsoluteExpiration(expiresUtc.Value); } options.SetSlidingExpiration(TimeSpan.FromMinutes(_sessionSettings.Value.TimeOut)); _cache.Set(key, ticket, options); return Task.FromResult(0); } public Task RetrieveAsync(string key) { if (!key.StartsWith(KeyPrefix)) key = KeyPrefix + key; AuthenticationTicket ticket; _cache.TryGetValue(key, out ticket); return Task.FromResult(ticket); } public Task RemoveAsync(string key) { if (!key.StartsWith(KeyPrefix)) key = KeyPrefix + key; _cache.Remove(key); return Task.FromResult(0); } } /// /// Ticketstore für AuthenticationTickets der diese initial von einer DB lädt und wieder speichern kann. /// Übersteht "Server-Resets" /// public class MemoryCachePersistedTicketStore : ITicketStore { private bool _initialized; private IServiceProvider _serivceProvider; private readonly IOptions _sessionSettings; private const string KeyPrefix = "AuthSessionStore-"; private IMemoryCache _cache; public MemoryCachePersistedTicketStore(IOptions sessionSettings, IServiceProvider serviceProvider) { _serivceProvider = serviceProvider; _sessionSettings = sessionSettings; _cache = new MemoryCache(new MemoryCacheOptions()); _initialized = false; } private async Task InitializeAsync() { using var scope = _serivceProvider.CreateScope(); var persistedTicketService = scope.ServiceProvider.GetRequiredService(); var items = await persistedTicketService.GetAllAsync(); foreach (var item in items) { var options = new MemoryCacheEntryOptions(); var expiresUtc = item.Expires; if (expiresUtc.HasValue) { options.SetAbsoluteExpiration(expiresUtc.Value); } options.SetSlidingExpiration(TimeSpan.FromMinutes(_sessionSettings.Value.TimeOut)); if (!_cache.TryGetValue(item.Key, out var value)) _cache.Set(item.Key, DeserializeFromBytes(item.Ticket), options); } _initialized = true; } public async Task ClearAll() { await Task.Delay(1); _cache.Dispose(); _cache = new MemoryCache(new MemoryCacheOptions()); } public async Task StoreAsync(AuthenticationTicket ticket) { if (!_initialized) await InitializeAsync(); var key = KeyPrefix + ticket.Principal.Identity.Name; await RenewAsync(key, ticket); return key; } public async Task RenewAsync(string key, AuthenticationTicket ticket) { if (!_initialized) await InitializeAsync(); if (!key.StartsWith(KeyPrefix)) key = KeyPrefix + key; var options = new MemoryCacheEntryOptions(); var expiresUtc = ticket.Properties.ExpiresUtc; if (expiresUtc.HasValue) { options.SetAbsoluteExpiration(expiresUtc.Value); } options.SetSlidingExpiration(TimeSpan.FromMinutes(_sessionSettings.Value.TimeOut)); _cache.Set(key, ticket, options); using var scope = _serivceProvider.CreateScope(); var persistedTicketService = scope.ServiceProvider.GetRequiredService(); var userId = key.Replace(KeyPrefix, ""); var expires = ticket.Properties.ExpiresUtc; var byteTicket = SerializeToBytes(ticket); await persistedTicketService.SaveAsync(key, userId, byteTicket, expires); await persistedTicketService.CommitAsync("System"); } public async Task RetrieveAsync(string key) { if (!_initialized) await InitializeAsync(); if (!key.StartsWith(KeyPrefix)) key = KeyPrefix + key; AuthenticationTicket ticket; _cache.TryGetValue(key, out ticket); return ticket; } public async Task RemoveAsync(string key) { if (!_initialized) await InitializeAsync(); if (!key.StartsWith(KeyPrefix)) key = KeyPrefix + key; _cache.Remove(key); using var scope = _serivceProvider.CreateScope(); var persistedTicketService = scope.ServiceProvider.GetRequiredService(); await persistedTicketService.RemoveAsync(key); await persistedTicketService.CommitAsync("System"); } private byte[] SerializeToBytes(AuthenticationTicket source) => TicketSerializer.Default.Serialize(source); private AuthenticationTicket DeserializeFromBytes(byte[] source) => source == null ? null : TicketSerializer.Default.Deserialize(source); } }