205 lines
7.1 KiB
C#
205 lines
7.1 KiB
C#
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.Distributed;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace gehGassi.Web.Auth
|
|
{
|
|
/// <summary>
|
|
/// Verteilter Ticketstore für AuthenticationTickets
|
|
/// </summary>
|
|
public class DistributedCacheTicketStore : ITicketStore
|
|
{
|
|
private readonly IOptions<SessionSettings> _sessionSettings;
|
|
private const string KeyPrefix = "AuthSessionStore-";
|
|
private readonly IDistributedCache _cache;
|
|
|
|
public DistributedCacheTicketStore(IOptions<SessionSettings> sessionSettings, IDistributedCache cache)
|
|
{
|
|
_sessionSettings = sessionSettings;
|
|
_cache = cache;
|
|
}
|
|
|
|
public async Task<string> 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 DistributedCacheEntryOptions();
|
|
var expiresUtc = ticket.Properties.ExpiresUtc;
|
|
if (expiresUtc.HasValue)
|
|
{
|
|
options.SetAbsoluteExpiration(expiresUtc.Value);
|
|
}
|
|
options.SetSlidingExpiration(TimeSpan.FromMinutes(_sessionSettings.Value.TimeOut));
|
|
|
|
var serializedTicket = TicketSerializer.Default.Serialize(ticket);
|
|
_cache.Set(key, serializedTicket, options);
|
|
|
|
return Task.FromResult(0);
|
|
}
|
|
|
|
public Task<AuthenticationTicket> RetrieveAsync(string key)
|
|
{
|
|
if (!key.StartsWith(KeyPrefix))
|
|
key = KeyPrefix + key;
|
|
|
|
AuthenticationTicket ticket = null;
|
|
|
|
var storedTicket = _cache.Get(key);
|
|
|
|
if (storedTicket != null)
|
|
{
|
|
ticket = TicketSerializer.Default.Deserialize(storedTicket);
|
|
}
|
|
return Task.FromResult(ticket);
|
|
}
|
|
|
|
public Task RemoveAsync(string key)
|
|
{
|
|
if (!key.StartsWith(KeyPrefix))
|
|
key = KeyPrefix + key;
|
|
|
|
_cache.Remove(key);
|
|
return Task.FromResult(0);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verteilter Ticketstore für AuthenticationTickets der diese initial von einer DB lädt und wieder speichern kann.
|
|
/// Übersteht "Server-Resets"
|
|
/// </summary>
|
|
public class DistributedCachePersistedTicketStore : ITicketStore
|
|
{
|
|
private bool _initialized;
|
|
private IServiceProvider _serivceProvider;
|
|
private readonly IOptions<SessionSettings> _sessionSettings;
|
|
private const string KeyPrefix = "AuthSessionStore-";
|
|
private readonly IDistributedCache _cache;
|
|
|
|
public DistributedCachePersistedTicketStore(IOptions<SessionSettings> sessionSettings, IDistributedCache cache, IServiceProvider serviceProvider)
|
|
{
|
|
_sessionSettings = sessionSettings;
|
|
_cache = cache;
|
|
_initialized = false;
|
|
_serivceProvider = serviceProvider;
|
|
}
|
|
|
|
private async Task InitializeAsync()
|
|
{
|
|
using var scope = _serivceProvider.CreateScope();
|
|
var persistedTicketService = scope.ServiceProvider.GetRequiredService<IPersistedTicketService>();
|
|
var items = await persistedTicketService.GetAllAsync();
|
|
foreach (var item in items)
|
|
{
|
|
var options = new DistributedCacheEntryOptions();
|
|
var expiresUtc = item.Expires;
|
|
if (expiresUtc.HasValue)
|
|
{
|
|
options.SetAbsoluteExpiration(expiresUtc.Value);
|
|
}
|
|
options.SetSlidingExpiration(TimeSpan.FromMinutes(_sessionSettings.Value.TimeOut));
|
|
|
|
if (await _cache.GetAsync(item.Key) == null)
|
|
_cache.Set(item.Key, item.Ticket, options);
|
|
}
|
|
_initialized = true;
|
|
}
|
|
|
|
public async Task<string> 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 DistributedCacheEntryOptions();
|
|
var expiresUtc = ticket.Properties.ExpiresUtc;
|
|
if (expiresUtc.HasValue)
|
|
{
|
|
options.SetAbsoluteExpiration(expiresUtc.Value);
|
|
}
|
|
options.SetSlidingExpiration(TimeSpan.FromMinutes(_sessionSettings.Value.TimeOut));
|
|
|
|
var serializedTicket = TicketSerializer.Default.Serialize(ticket);
|
|
_cache.Set(key, serializedTicket, options);
|
|
|
|
using var scope = _serivceProvider.CreateScope();
|
|
var persistedTicketService = scope.ServiceProvider.GetRequiredService<IPersistedTicketService>();
|
|
|
|
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<AuthenticationTicket> RetrieveAsync(string key)
|
|
{
|
|
if (!_initialized)
|
|
await InitializeAsync();
|
|
|
|
if (!key.StartsWith(KeyPrefix))
|
|
key = KeyPrefix + key;
|
|
|
|
AuthenticationTicket ticket = null;
|
|
|
|
var storedTicket = _cache.Get(key);
|
|
|
|
if (storedTicket != null)
|
|
{
|
|
ticket = TicketSerializer.Default.Deserialize(storedTicket);
|
|
}
|
|
return ticket;
|
|
}
|
|
|
|
public async Task RemoveAsync(string key)
|
|
{
|
|
if (!_initialized)
|
|
await InitializeAsync();
|
|
|
|
if (!key.StartsWith(KeyPrefix))
|
|
key = KeyPrefix + key;
|
|
|
|
using var scope = _serivceProvider.CreateScope();
|
|
var persistedTicketService = scope.ServiceProvider.GetRequiredService<IPersistedTicketService>();
|
|
var ticket = await RetrieveAsync(key);
|
|
|
|
_cache.Remove(key);
|
|
|
|
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);
|
|
}
|
|
}
|