如果我使用本机依赖注入容器向我的ASP.Net核心应用程序添加cookie身份验证,并使用cookie身份验证选项。那么如何在启动后在运行时替换身份验证选项?例如,如果我想在应用程序运行时更改cookie过期。我无法弄清楚如何用它的选项替换身份验证处理程序以影响更改。
启动时代码添加身份验证:
public static IServiceCollection ConfigureOAuth(this IServiceCollection services)
{
var appSettings = services.BuildServiceProvider().GetService<IOptions<AppSettings>>();
return services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, (o) =>
{
o.ExpireTimeSpan = TimeSpan.FromHours(appSettings.Value.HostOptions.SessionLifespanHours);
})
.Services;
}
代码在运行时替换身份验证:
/// <summary>
/// Replace authentication options with new ones read from configuration.
/// 1). Remove old services
/// 2.) Reload the configuration
/// 3.) Add the authentication scheme with options read from the latest configuration
/// </summary>
private static void ReplaceServices(IServiceCollection services, IHostingEnvironment env)
{
ClearServices(services);
services.Configure<AppSettings>(StartupConfiguration.BuildConfigurationRoot(env).GetSection("App"));
var provider = services.BuildServiceProvider();
var appSettings = provider.GetService<IOptions<AppSettings>>();
services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureCookieAuthenticationOptions>());
services.AddScheme<CookieAuthenticationOptions, CookieAuthenticationHandler>(CookieAuthenticationDefaults.AuthenticationScheme, (o) =>
{
o.ExpireTimeSpan = TimeSpan.FromHours(appSettings.Value.HostOptions.SessionLifespanHours);
});
}
/// <summary>
/// Clear stale dependencies: application settings configured from appsettings.json,
/// authentication options and cookie authentication handler and options
/// </summary>
private static void ClearServices(IServiceCollection services)
{
var staleTypes = new List<Type>
{
typeof(IConfigureOptions<AppSettings>),
typeof(IConfigureOptions<AuthenticationOptions>),
typeof(IPostConfigureOptions<CookieAuthenticationOptions>),
typeof(IConfigureOptions<CookieAuthenticationOptions>),
typeof(CookieAuthenticationHandler)
};
foreach (var staleType in staleTypes)
{
var staleService = services.FirstOrDefault(s => s.ServiceType.Equals(staleType));
services.Remove(staleService);
}
}
答案 0 :(得分:1)
Asp.net核心本机配置重新加载可能有点不稳定。如果服务依赖于在运行时更改的应用程序设置,则不必在启动时将这些设置作为IOptions注入。另一种方法是编写设置提供程序,在从文件系统观察程序收到事件通知时重新加载设置的缓存副本。这种方法消除了将配置作为DI服务的需要,您不再需要依赖重新加载令牌。流程如下:
这里的关键是创建一个认证处理程序可以成功使用并始终具有实时值的选项服务。为此,您需要实现IOptionsMonitor。
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddSingleton<IOptionsMonitor<CookieAuthenticationOptions>, CookieAuthenticationConfigurator>()
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
}
IOptionsMonitor实现:
{
internal class CookieAuthenticationConfigurator : IOptionsMonitor<CookieAuthenticationOptions>
{
private readonly FileConfigurationBuilder ConfigProvider;
private readonly IHostingEnvironment Environment;
private readonly IDataProtectionProvider DataProtectionProvider;
private readonly IMessageHub Hub;
public CookieAuthenticationConfigurator(FileConfigurationBuilder configProvider, IDataProtectionProvider dataProtectionProvider, IMessageHub hub, IHostingEnvironment environment)
{
ConfigProvider = configProvider;
Environment = environment;
DataProtectionProvider = dataProtectionProvider;
Hub = hub;
Initialize();
}
private void Initialize()
{
Hub.Subscribe<ConfigurationChangeEvent>(_ =>
{
Build();
});
Build();
}
private void Build()
{
var hostOptions = ConfigProvider.Get<HostOptions>("HostOptions");
options = new CookieAuthenticationOptions
{
ExpireTimeSpan = TimeSpan.FromHours(hostOptions.SessionLifespanHours)
};
}
private CookieAuthenticationOptions options;
public CookieAuthenticationOptions CurrentValue => options;
public CookieAuthenticationOptions Get(string name)
{
PostConfigureCookieAuthenticationOptions op = new PostConfigureCookieAuthenticationOptions(DataProtectionProvider);
op.PostConfigure(name, options);
return options;
}
public IDisposable OnChange(Action<CookieAuthenticationOptions, string> listener)
{
throw new NotImplementedException();
}
}
}