c# - 使用 IdentityServer4 加载项目时 DefaultUserSession 中的 NullReferenceException

标签 c# docker kubernetes .net-core identityserver4

我正在运行一个使用 Nuget 安装 IdentityServer4 的 dotnet core 2.2 应用程序。当我构建一个 docker 容器并运行时,一切正常。当我将此容器部署到我的 Google Kubernetes Engine 集群时,它在启动时失败,并显示以下内容:

{
 insertId:  "18ykz2ofg4ipm0"  
 labels: {
  compute.googleapis.com/resource_name:  "fluentd-gcp-v3.1.0-nndnb"   
  container.googleapis.com/namespace_name:  "my_namespace"   
  container.googleapis.com/pod_name:  "identity-deployment-5b8bd8745b-qn2v8"   
  container.googleapis.com/stream:  "stdout"   
 }
 logName:  "projects/my_project/logs/app"  
 receiveTimestamp:  "2018-12-07T21:09:25.708527406Z"  
 resource: {
  labels: {
   cluster_name:  "my_cluster"    
   container_name:  "app"    
   instance_id:  "4238697312444637243"    
   namespace_id:  "my_namespace"    
   pod_id:  "identity-deployment-5b8bd8745b-qn2v8"    
   project_id:  "my_project"    
   zone:  "europe-west2-b"    
  }
  type:  "container"   
 }
 severity:  "INFO"  
 textPayload:  "System.NullReferenceException: Object reference not set 
to an instance of an object.
   at 
IdentityServer4.Services.DefaultUserSession.RemoveSessionIdCookieAsync()
   at 
IdentityServer4.Services.DefaultUserSession.EnsureSessionIdCookieAsync()
   at 
IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events) 
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)
"  
 timestamp:  "2018-12-07T21:09:17Z"  
}

正如我所提到的,这在本地完美运行,并且在 docker 容器中运行时,只有在 Kubernetes 中我才会看到这些错误。

我不确定我在这里错过了 kubernetes 什么,但非常感谢任何帮助。

最佳答案

在过去的几天里,这让我很烦恼。我怀疑这与最近在应用程序构建器配置中弃用前一种机制有关:

   app.UseAuthentication().UseCookieAuthentication();  <-- no longer valid and apparently will not even compile now.

这已在 ConfigureServices 部分中替换为以下内容:
  services.AddAuthentication("YourCookieName")
    .AddCookie("YourCookieName", options =>
    {
      options.ExpireTimeSpan = TimeSpan.FromDays(30.0);
    });

虽然我不确定 identityserver4 的确切重大更改是什么,但在克隆 identityserver4 组件并进行调试后,我能够隔离 DefaultUserSession 的构造函数,它采用了一个作为 null 到达的 IHttpContextAccessor:

有问题的构造函数:
    public DefaultUserSession(
        IHttpContextAccessor httpContextAccessor,
        IAuthenticationSchemeProvider schemes,
        IAuthenticationHandlerProvider handlers,
        IdentityServerOptions options,
        ISystemClock clock,
        ILogger<IUserSession> logger)
    { ...

以下解决方案可以帮助您克服错误,但希望 identityserver4 在不久的将来的版本中能够解决这个问题。

您需要在 ConfigureServices 中添加一个 IHttpContextAccessor 服务:
public override void ConfigureServices(IServiceCollection services)
{
  ... other code omitted ...
  services.AddScoped<IHttpContextAccessor>(provider => new 
       LocalHttpContextAccessor(provider));
  ... other code omitted ...
}

LocalHttpContextAccessor 只是配置类中的一个私有(private)类,如下所示:
private class LocalHttpContextAccessor : IHttpContextAccessor
{
  public IServiceProvider serviceProvider { get; private set; }
  public HttpContext httpContext { get; set; }

  public LocalHttpContextAccessor(IServiceProvider serviceProvider)
  {
    this.serviceProvider = serviceProvider;
    this.httpContext = null;
  }

  public HttpContext HttpContext
  {
    get
    {
      return this.httpContext;
    }
    set
    {
      this.httpContext = null;
    }
  }
}

问题是在配置服务时,没有设置当前上下文,所以我在应用程序构建器配置阶段将其设置在 using block 中:
public override void Configure(IApplicationBuilder app,
  IHostingEnvironment env)
{
  app.Use(async (context, next) =>
  {
    IHttpContextAccessor httpContextAccessor;

    httpContextAccessor = context.RequestServices.GetRequiredService<IHttpContextAccessor>();
    if (httpContextAccessor is LocalHttpContextAccessor)
    {
      ((LocalHttpContextAccessor)httpContextAccessor).httpContext = context;
    }
    await next();
  });
  ... other code omitted ...
  app.UseIdentityServer();

这将在运行修复错误的身份服务器代码之前设置 http 上下文。应为每个请求单独创建范围服务。我最近才从 .net 框架完全投入到 .net 核心中,因此如果该代码中存在可能导致泄漏或不良生命周期的范围或 DI 问题,我将不胜感激。也就是说,至少该代码可以防止身份服务器 4 与核心 2.2+ 崩溃。

关于c# - 使用 IdentityServer4 加载项目时 DefaultUserSession 中的 NullReferenceException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53676909/

相关文章:

docker - 如何在不杀死原来的pod的情况下更改k8s的pod限制?

c# - 在文档查看器中显示 XPS 文档

c# - XNA:防止方法返回

docker - 将 BuildKit 与 Docker 一起使用时,如何查看 RUN 命令的输出?

docker - docker 和 cricontainerd 可以共存吗

visual-studio - 在 docker 容器中安装 VS2017

Kubernetes 存储持久文件

c# - 如何在 Npgsql 中为查询提供表名作为命令参数?

c# - 从通用列表中选择底部 N

kubernetes - 看不懂kubernetes `When should you use a startup probe`的死锁场景?