【问题标题】:Set a custom SessionStore for ConfigureApplicationCookie without BuildServiceProvider()在没有 BuildServiceProvider() 的情况下为 ConfigureApplicationCookie 设置自定义 SessionStore
【发布时间】:2020-06-09 04:08:45
【问题描述】:

我有一个使用 Redis 分布式缓存和 cookie 身份验证的 .NET Core 3 项目(最近从 2.2 升级)。

它目前看起来像这样:

public void ConfigureServices(IServiceCollection services)
{
    // Set up Redis distributed cache
    services.AddStackExchangeRedisCache(...);

    ...

    services.ConfigureApplicationCookie(options =>
    {
        ...
        // Get a service provider to get the distributed cache set up above
        var cache = services.BuildServiceProvider().GetService<IDistributedCache>();

         options.SessionStore = new MyCustomStore(cache, ...);
    }):
}

问题是BuildServiceProvider()导致构建错误:

Startup.cs(...):警告 ASP0000:从应用程序代码中调用“BuildServiceProvider”会导致创建单例服务的额外副本。考虑将依赖注入服务等替代方案作为“配置”的参数。

这似乎不是一个选项 - ConfigureApplicationCookieStartup.ConfigureServices 中,只能配置新服务,Startup.Configure 可以使用新服务,但不能覆盖 CookieAuthenticationOptions.SessionStore 成为我的自定义商店.

我尝试在ConfigureApplicationCookie 之前添加services.AddSingleton&lt;ITicketStore&gt;(p =&gt; new MyCustomRedisStore(cache, ...)),但这被忽略了。

显式设置CookieAuthenticationOptions.SessionStore 似乎是唯一让它使用本地内存存储以外的任何东西的方法。

我在网上找到的每个示例都使用BuildServiceProvider()

理想情况下,我想做这样的事情:

services.ConfigureApplicationCookieStore(provider => 
{
    var cache = provider.GetService<IDistributedCache>();
    return new MyCustomStore(cache, ...);
});

或者

public void Configure(IApplicationBuilder app, ... IDistributedCache cache)
{
    app.UseApplicationCookieStore(new MyCustomStore(cache, ...));
}

然后CookieAuthenticationOptions.SessionStore 应该只使用我在那里配置的任何内容。

如何让应用程序 cookie 使用注入的存储?

【问题讨论】:

    标签: asp.net-core .net-core dependency-injection stackexchange.redis cookie-authentication


    【解决方案1】:

    参考Use DI services to configure options

    如果您的自定义存储的所有依赖项都是可注入的,那么只需将您的存储和所需的依赖项注册到服务集合并使用 DI 服务来配置选项

    public void ConfigureServices(IServiceCollection services) {
        // Set up Redis distributed cache
        services.AddStackExchangeRedisCache(...);
    
        //register my custom store
        services.AddSingleton<ITicketStore, MyCustomRedisStore>();
    
        //...
    
        //Use DI services to configure options
        services.AddOptions<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme)
            .Configure<ITicketStore>((options, store) => {
                options.SessionStore = store;
            });
    
        services.ConfigureApplicationCookie(options => {
            //do nothing
        }):
    }
    

    如果没有,则解决实际注册的问题

    例如

    //Use DI services to configure options
    services.AddOptions<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme)
        .Configure<IDistributedCache>((options, cache) => {
            options.SessionStore = new MyCustomRedisStore(cache, ...);
        });
    

    注意:

    ConfigureApplicationCookie 使用 named 选项实例。 - @KirkLarkin

    public static IServiceCollection ConfigureApplicationCookie(this IServiceCollection services, Action<CookieAuthenticationOptions> configure)
            => services.Configure(IdentityConstants.ApplicationScheme, configure);
    

    将选项添加到服务时需要包含名称。

    【讨论】:

    • Hrm,说得太早了.AddOptions&lt;CookieAuthenticationOptions&gt;() 似乎是这样,但它并没有击中.Configure 方法内的代码。
    • @Keith 嗯。有趣的。换个顺序试试。可能是第二个调用覆盖了第一个。
    • 这似乎没有什么区别,我传递给Configure的内容也没有。我认为AddOptions&lt;CookieAuthenticationOptions&gt; 只是被忽略了,可能是由于ConfigureApplicationCookie 的实现是什么。
    • ConfigureApplicationCookie 使用 named 选项实例。我认为你可以使用类似services.AddOptions&lt;CookieAuthenticationOptions&gt;(IdentityConstants.ApplicationScheme)...
    【解决方案2】:

    为了在 .NET Core 3.0 中实现 Redis 票证,我们执行了以下操作,这是上面的最终形式::

    services.AddSingleton<ITicketStore, RedisTicketStore>();
    services.AddOptions<CookieAuthenticationOptions>(CookieAuthenticationDefaults.AuthenticationScheme)
         .Configure<ITicketStore>((options, store) => {
             options.SessionStore = store;
         });
    
    
    services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
        .AddIdentityServerAuthentication(options =>
        {
               // ...configure identity server options
        }).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
    

    这是一个 Redis 实现:

    public class RedisTicketStore : ITicketStore
    {
        private const string KeyPrefix = "AuthSessionStore-";
        private IDistributedCache cache;
    
        public RedisTicketStore(IDistributedCache cache)
        {
            this.cache = cache;
        }
    
        public async Task<string> StoreAsync(AuthenticationTicket ticket)
        {
            var guid = Guid.NewGuid();
            var key = KeyPrefix + guid.ToString();
            await RenewAsync(key, ticket);
            return key;
        }
    
        public Task RenewAsync(string key, AuthenticationTicket ticket)
        {
            var options = new DistributedCacheEntryOptions();
            var expiresUtc = ticket.Properties.ExpiresUtc;
            if (expiresUtc.HasValue)
            {
                options.SetAbsoluteExpiration(expiresUtc.Value);
            }
            byte[] val = SerializeToBytes(ticket);
            cache.Set(key, val, options);
            return Task.FromResult(0);
        }
    
        public Task<AuthenticationTicket> RetrieveAsync(string key)
        {
            AuthenticationTicket ticket;
            byte[] bytes = null;
            bytes = cache.Get(key);
            ticket = DeserializeFromBytes(bytes);
            return Task.FromResult(ticket);
        }
    
        public Task RemoveAsync(string key)
        {
            cache.Remove(key);
            return Task.FromResult(0);
        }
    
        private static byte[] SerializeToBytes(AuthenticationTicket source)
        {
            return TicketSerializer.Default.Serialize(source);
        }
    
        private static AuthenticationTicket DeserializeFromBytes(byte[] source)
        {
            return source == null ? null : TicketSerializer.Default.Deserialize(source);
        }
    }
    

    Redis 实现来自:https://mikerussellnz.github.io/.NET-Core-Auth-Ticket-Redis/

    【讨论】:

      猜你喜欢
      • 2020-10-07
      • 1970-01-01
      • 1970-01-01
      • 2014-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多