无法让分布式缓存与 Identity Server 一起使用

Posted

技术标签:

【中文标题】无法让分布式缓存与 Identity Server 一起使用【英文标题】:Unable to get distributed cache to work with Identity Server 【发布时间】:2021-11-23 19:04:15 【问题描述】:

我在 MSDN 中介绍了使用 DB 为 suggested 的分布式缓存。目的是让我们的 IDP 服务器在 Kubernetes 上的多个 pod 上工作。在 Startup.cs 中,我像这样添加服务。

services.AddDistributedSqlServerCache(options =>

    options.ConnectionString = Configuration.GetConnectionString("DbTarget");
    options.ExpiredItemsDeletionInterval = new TimeSpan(10, 0, 0);
    options.SchemaName = "dbo";
    options.TableName = "Pokemons";
);
services.AddAuthorization(options => ... );
services.AddDbContext<AppDbContext>(ContextOptions());
services.AddIdentity<AppUser, AppRole>()
    .AddEntityFrameworkStores<AppDbContext>();

我检查了数据库,可以确认有一个与我们的选项相对应的表。但是,它是空的,因此目前没有可用的分布式缓存信息。根据this,我应该请求IDS4的默认存储,我尝试通过以下代码来完成。 (我使用的不是AddOpenIdConnect(...),而是AddIdentityServerAuthentication(...)。不过,由于IDS4 遵循OIDC 标准,因此我认为包含在内。)

services.AddIdentityServer(Ids4Options())
    .AddAspNetIdentity<AppUser>()
    .AddOperationalStore(OperationOptions())
    .AddConfigurationStore(ConfigOptions())
    .AddProfileService<ProfileService>()
    .AddDeveloperSigningCredential();

services.ConfigureApplicationCookie(options =>

    options.ExpireTimeSpan = TimeSpan.FromSeconds(55);
    options.SlidingExpiration = false;
);

services.AddHealthChecks();
services.AddCors(...);

services.AddOidcStateDataFormatterCache();
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
    .AddIdentityServerAuthentication(options =>
     
         options.Authority = Configuration["Env:BaseUrl"];
     );

我预计如果分布式缓存生效并设置了数据格式化程序,我的数据库中的表会在登录时被填充。但这不会发生。在构造函数中使用 DI 访问缓存的测试有效,当我执行 this 之类的内容时,我会看到数据库中的条目。

public MyClass (IDistributedCache cache)  Cache = cache; 
...
byte[] data = Encoding.ASCII.GetBytes("roo");
await Cache.SetAsync("kanga", data);

an issue on GitHub 建议明确指定模式,如下所示。遗憾的是,这并没有改变我的情况。

service.AddOidcStateDataFormatterCache(
  IdentityServerAuthenticationDefaults.AuthenticationScheme)

当我在本地执行项目时,在验证用户凭据有效后调用HttpContext.SignInAsync() 时,我会看到两个cookie 存储在浏览器的应用程序选项卡中。我期待与这些相对应的东西也将存储在数据库中。我的同事们在switching to SingalR 上提出了建议。但是,我看不出将 chache 提供程序更改为 Redis 等将如何解决任何问题,因为问题不是负载,而是不存在存储的信息。我还验证了表dbo.PersistedGrants 是活跃的,充满了价值。努力证明的冰山一角:irrelevant、tumbleweed、theoretical、already implemented。基于搜索键的其他建议中的相同主题。

显然,缺少启用分布式登录的附加步骤。或者,可能,我做错了什么。目前,我没有其他线索(尽管进行了广泛的谷歌搜索),并且由于缺乏解决问题或进一步调查的想法而陷入困境。

【问题讨论】:

【参考方案1】:

我设法解决了这个问题,大汗淋漓。第一个提示来自this answer,表明我使用的证书在多 pod 环境中不可行。请注意,以前版本的 .NET 应用了不同的方法(AddTestCredential() 或类似的方法),现在已经过时,取而代之的是下面的方法。

services. ...
  //.AddDeveloperSigningCredential();
  .AddSigningCredential(cert);

有关于如何创建证书文件的博客。它可能会涉及很多黑魔法,例如创建和转换文件、复合子证书、选择域等。它既复杂又困难。我的建议是 - 关注博客并希望获得最好的结果。证书最终可以通过下面的简单代码或使用提供证书密钥的服务来分发。

string path = base + "/certificate.pfx";
string pass = Configuration.GetValue<string>(...);
X509Certificate2 cert = new X509Certificate2(path, pass);

一旦我们这样做了(我们我的意思是和我一起骑着霰弹枪的同事),一切都开始按预期运行。问题显然不在于分布式缓存,而是由于使用 AddDeveloperSigningCredential() 动态创建了不同的证书而访问它。

在我看来,documented 应该更明显更好。一些要检查的资源(没有声称是完整的)来这里。

Certificate creation (manually, sort of graspable) Certificate generation (programmatically, confusing as duck) Accessibility alteration Converting format Broader discussion about certificates Service based certificate injection Service for cert distribution

【讨论】:

以上是关于无法让分布式缓存与 Identity Server 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

Identity Server 4 无法验证来自 localhost 的受保护 API 的令牌

ASP.NET Core分布式项目实战IdentityServer4登录中心oauth密码模式identity server4实现

Windows Server AppFabric分布式缓存研究

SQL Server 错误:“无法为标识列插入显式值”,即使我 SET IDENTITY_INSERT ON

SignalR 授权无法在带有 Identity Server 的 asp.net core angular SPA 中开箱即用

mysql @@identity 与 sql-server last_insert_id()