|
using System; |
|
using Microsoft.AspNetCore.Authentication.Cookies; |
|
using Microsoft.AspNetCore.Http; |
|
using Microsoft.AspNetCore.Identity; |
|
using Microsoft.Extensions.Options; |
|
using Microsoft.Extensions.DependencyInjection; |
|
using System.Collections.Generic; |
|
using Microsoft.Extensions.Logging; |
|
using Microsoft.Extensions.Primitives; |
|
|
|
namespace AstonishingLab.MultiTenancy |
|
{ |
|
/// <summary> |
|
/// Inspired on Cloudscrib. |
|
/// https://github.com/joeaudette/cloudscribe/blob/master/src/cloudscribe.Core.Identity/SiteCookieAuthenticationOptions.cs |
|
/// </summary> |
|
public class SiteCookieAuthenticationOptions : IOptionsMonitor<CookieAuthenticationOptions> |
|
{ |
|
private readonly SiteCookieAuthenticationConfiguration siteCookieAuthenticationConfiguration; |
|
private readonly IHttpContextAccessor httpContextAccessor; |
|
private readonly ILogger log; |
|
private readonly IOptionsMonitorCache<CookieAuthenticationOptions> cache; |
|
private readonly IOptionsFactory<CookieAuthenticationOptions> factory; |
|
private readonly IEnumerable<IOptionsChangeTokenSource<CookieAuthenticationOptions>> sources; |
|
internal event Action<CookieAuthenticationOptions, string> _onChange; |
|
|
|
public SiteCookieAuthenticationOptions( |
|
IOptionsFactory<CookieAuthenticationOptions> factory, |
|
IEnumerable<IOptionsChangeTokenSource<CookieAuthenticationOptions>> sources, |
|
IOptionsMonitorCache<CookieAuthenticationOptions> cache, |
|
IHttpContextAccessor httpContextAccessor, |
|
IOptions<SiteCookieAuthenticationConfiguration> siteCookieAuthenticationConfiguration, |
|
ILogger<SiteCookieAuthenticationOptions> logger) |
|
{ |
|
this.httpContextAccessor = httpContextAccessor; |
|
log = logger; |
|
|
|
this.factory = factory; |
|
this.sources = sources; |
|
this.cache = cache; |
|
this.siteCookieAuthenticationConfiguration = siteCookieAuthenticationConfiguration.Value; |
|
foreach (var source in this.sources) |
|
{ |
|
ChangeToken.OnChange<string>( |
|
() => source.GetChangeToken(), |
|
(name) => InvokeChanged(name), |
|
source.Name); |
|
} |
|
} |
|
|
|
private CookieAuthenticationOptions ResolveOptions(string scheme) |
|
{ |
|
var services = httpContextAccessor.HttpContext.RequestServices; |
|
var options = new CookieAuthenticationOptions(); |
|
|
|
var cookieOptionsInitializer = services.GetRequiredService<IPostConfigureOptions<CookieAuthenticationOptions>>(); |
|
cookieOptionsInitializer.PostConfigure(scheme, options); |
|
|
|
if (siteCookieAuthenticationConfiguration.PerRequestAction != null) |
|
{ |
|
siteCookieAuthenticationConfiguration.PerRequestAction(httpContextAccessor.HttpContext, options, scheme); |
|
} |
|
return options; |
|
} |
|
|
|
public CookieAuthenticationOptions CurrentValue |
|
{ |
|
get |
|
{ |
|
return ResolveOptions(IdentityConstants.ApplicationScheme); |
|
} |
|
} |
|
|
|
public CookieAuthenticationOptions Get(string name) |
|
{ |
|
return ResolveOptions(name); |
|
} |
|
|
|
private void InvokeChanged(string name) |
|
{ |
|
name = name ?? Options.DefaultName; |
|
cache.TryRemove(name); |
|
var options = Get(name); |
|
if (_onChange != null) |
|
{ |
|
_onChange.Invoke(options, name); |
|
} |
|
} |
|
|
|
public IDisposable OnChange(Action<CookieAuthenticationOptions, string> listener) |
|
{ |
|
log.LogDebug("onchange invoked"); |
|
|
|
var disposable = new ChangeTrackerDisposable(this, listener); |
|
_onChange += disposable.OnChange; |
|
return disposable; |
|
} |
|
|
|
|
|
internal class ChangeTrackerDisposable : IDisposable |
|
{ |
|
private readonly Action<CookieAuthenticationOptions, string> _listener; |
|
private readonly SiteCookieAuthenticationOptions _monitor; |
|
|
|
public ChangeTrackerDisposable(SiteCookieAuthenticationOptions monitor, Action<CookieAuthenticationOptions, string> listener) |
|
{ |
|
_listener = listener; |
|
_monitor = monitor; |
|
} |
|
|
|
public void OnChange(CookieAuthenticationOptions options, string name) => _listener.Invoke(options, name); |
|
|
|
public void Dispose() => _monitor._onChange -= OnChange; |
|
} |
|
} |
|
} |