【问题标题】:Distributed IdentityServer4 .net core (multi instance) issues HttpContext must not be null分布式 IdentityServer4 .net 核心(多实例)问题 HttpContext 不能为空
【发布时间】:2020-11-19 14:03:20
【问题描述】:

因此,我们设置了带有 .net 核心的 IdentityServer4,仅在一个实例上一切都按预期工作,但是当我们决定旋转更多 Identity Server 实例时,我们在从客户端登录或退出时随机遇到问题。

我关注了这些文档:Distributed IdentityServer

这就是我添加 IDS4 的方式

            _identityBuilder = services.AddIdentityServer(options =>
                {
                    options.Events.RaiseErrorEvents = true;
                    options.Events.RaiseInformationEvents = true;
                    options.Events.RaiseFailureEvents = true;
                    options.Events.RaiseSuccessEvents = true;
                    options.EmitStaticAudienceClaim = true;
                })
                .AddInMemoryIdentityResources(Config.IdentityResources)
                .AddInMemoryApiResources(Configuration.GetSection("idServer:apiResources"))
                .AddInMemoryApiScopes(Configuration.GetSection("idServer:apiScopes"))
                .AddInMemoryClients(Configuration.GetSection("idServer:clients"))
                .AddAspNetIdentity<HeimdallUserEntity>()                    
            ;

另外因为服务器要分布式我也加了这段代码,注意下面的证书是在实例之间共享的(所以每个实例都使用同一个证书)

    _identityBuilder.AddSigningCredential(certificate);
    services.AddDataProtection()
                .SetApplicationName(Assembly.GetExecutingAssembly().FullName)           
                .PersistKeysToDbContext<MainDbContext>()
                .ProtectKeysWithCertificate(certificate);

但是,即使使用此设置,我在从使用 PKCE 的客户端登录和注销时(随机)也遇到问题。我遇到的问题是我随机收到此异常:

HttpContext must not be null.

从以下位置抛出:Microsoft.AspNetCore.Identity -> SignInManager -> SignOutAsync() 并来自:Microsoft.AspNetCore.Identity -> SignInManager -> SignInWithClaimsAsync(TUser user, AuthenticationProperties authenticationProperties, IEnumerable additionalClaims)

在此处的 SignInManager.cs 类中处理并抛出此异常:

 public HttpContext Context
    {
        get
        {
            var context = _context ?? _contextAccessor?.HttpContext;
            if (context == null)
            {
                throw new InvalidOperationException("HttpContext must not be null.");
            }
            return context;
        }
        set
        {
            _context = value;
        }
    }

另请注意,client_credentials 工作正常,我请求一个令牌,并且在多个实例/副本上一切正常。

:: 更新 ::

我终于找到了这个问题,与Identity Server无关,在我们的系统中我们使用Microsoft Orleans,并且我们有一个Grain 注入 UserService 并且 UserService 注入 SignInManager,结果 SignInManager 需要 SignInManager strong>HttpContext 能够解析服务,但是由于 orleans 没有提供 IHttpContextAccessor,所以 HttpContext 永远无法解析:/

现在我们直接调用 UserService。但是如果能够创建/找到一个不依赖于 HttpContext 的 SignInManager(尤其是因为它只使用它来解析其他服务),那就太好了

【问题讨论】:

  • 你的管道一定有问题,所以 HttpContext 没有及时初始化。你能展示你的 Configure() 方法吗?
  • client_credentials 在一次往返中产生结果(因此每次它消耗唯一的实例),而 access_code(与任何其他交互式)流需要多次重定向,其中每个下一个都可以由另一个实例处理
  • 也有类似的issue in .net core 2.2,但已修复。无论如何,您可以从那里重用一些方法来弄清楚您的环境中发生了什么
  • @d_f 我的配置很正常:app.UseIdentityServer(); app.UseAuthentication(); app.UseAuthorization();

标签: asp.net-core identityserver4


【解决方案1】:

您是否在不同实例中使用相同的令牌签名凭据并使用 AddSigningCredential 方法添加它们?

不要认为这是这里的核心问题,但您应该知道,当您使用 PersistKeysToDbContext 并跨服务共享它时,当多个服务尝试写入同一个表时,可能还会出现竞争条件数据库。尤其是在启动时(当数据库为空时)和密钥每 90 天轮换一次时。

【讨论】:

  • 这不仅仅在启动时发生
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-09
  • 2019-11-16
  • 1970-01-01
  • 1970-01-01
  • 2019-09-25
  • 2021-05-12
  • 2012-09-18
相关资源
最近更新 更多