我正在使用扩展名:
services.AddOidcStateDataFormatterCache();
在Asp.Net Core中,将状态存储在使用Redis实现的分布式缓存中:
services.AddStackExchangeRedisCache(options => {
options.Configuration = Configuration[RedisConnection];
});
是否存在用于控制在缓存中创建的键的TTL的设置?
答案 0 :(得分:1)
已经reported。等待回应。 (请注意,那里也需要这个!)
目前,我们使用一个丑陋的继承者。丑陋的原因是该库没有虚拟方法,并且还需要一个辅助程序internal class ConfigureOpenIdConnectOptionsTTL : IPostConfigureOptions<OpenIdConnectOptions>
(主要是再次复制和粘贴),但是至少它可以解决“生产中的redis缓慢”问题。
public class DistributedCacheStateDataFormatterTTL:
DistributedCacheStateDataFormatter, ISecureDataFormat<AuthenticationProperties>
{
public static readonly TimeSpan DefaultCacheDuration = TimeSpan.FromMinutes(5);
private readonly IHttpContextAccessor _httpContext;
private readonly string _name;
public DistributedCacheStateDataFormatterTTL(
IHttpContextAccessor httpContext, string name) : base(httpContext, name)
{
_httpContext = httpContext;
_name = name;
}
private string CacheKeyPrefix => "DistributedCacheStateDataFormatter";
private IDistributedCache Cache =>
_httpContext.HttpContext.RequestServices.GetRequiredService<IDistributedCache>();
private IDataProtector Protector =>
_httpContext.HttpContext.RequestServices
.GetRequiredService<IDataProtectionProvider>()
.CreateProtector(CacheKeyPrefix, _name);
string ISecureDataFormat<AuthenticationProperties>
.Protect(AuthenticationProperties data)
{
return ((ISecureDataFormat<AuthenticationProperties>)this).
Protect(data, string.Empty);
}
string ISecureDataFormat<AuthenticationProperties>
.Protect(AuthenticationProperties data, string purpose)
{
var key = Guid.NewGuid().ToString();
var cacheKey = $"{CacheKeyPrefix}-{purpose}-{key}";
var json = JsonConvert.SerializeObject(data, new JsonSerializerSettings()
{
DefaultValueHandling = DefaultValueHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
});
var options = new DistributedCacheEntryOptions();
if (data.ExpiresUtc.HasValue)
options.SetAbsoluteExpiration(data.ExpiresUtc.Value);
else
options.SetSlidingExpiration(DefaultCacheDuration);
// Rather than encrypt the full AuthenticationProperties
// cache the data and encrypt the key that points to the data
Cache.SetString(cacheKey, json, options);
return Protector.Protect(key);
}
}
internal class ConfigureOpenIdConnectOptionsTTL : IPostConfigureOptions<OpenIdConnectOptions>
{
private string[] _schemes;
private readonly IHttpContextAccessor _httpContextAccessor;
public ConfigureOpenIdConnectOptionsTTL(string[] schemes, IHttpContextAccessor httpContextAccessor)
{
_schemes = schemes ?? throw new ArgumentNullException(nameof(schemes));
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
public void PostConfigure(string name, OpenIdConnectOptions options)
{
// no schemes means configure them all
if (_schemes.Length == 0 || _schemes.Contains(name))
{
options.StateDataFormat = new DistributedCacheStateDataFormatterTTL(_httpContextAccessor, name);
}
}
public static IServiceCollection AddOidcStateDataFormatterCache(
IServiceCollection services,
params string[] schemes)
{
services.RemoveAll<IPostConfigureOptions<OpenIdConnectOptions>>();
services.AddSingleton<IPostConfigureOptions<OpenIdConnectOptions>>(
svcs => new ConfigureOpenIdConnectOptionsTTL(
schemes,
svcs.GetRequiredService<IHttpContextAccessor>())
);
return services;
}
}