C# ASP.NET核心中间件在身份验证之前执行

C# ASP.NET核心中间件在身份验证之前执行,c#,asp.net-core,C#,Asp.net Core,作为登录流程的一部分,我需要检查用户是否有权访问我正在编写的应用程序。我通过使用用户id查询遗留数据库来实现这一点。之后,我想将遗留id添加到请求中,这样我就不必每次都查找它。因此,我构建了一个策略,用于检索登录用户的旧id并将其添加到请求中。然后我编写了一个LoggingMiddleware,将该遗留id添加为日志属性 两者都很好地工作,但执行顺序错误。首先执行中间件,然后执行身份验证策略。所以我经常记录“匿名”而不是我想记录的id。我的Startup类有正确的顺序(我想),所以我不明白为什么

作为登录流程的一部分,我需要检查用户是否有权访问我正在编写的应用程序。我通过使用用户id查询遗留数据库来实现这一点。之后,我想将遗留id添加到请求中,这样我就不必每次都查找它。因此,我构建了一个策略,用于检索登录用户的旧id并将其添加到请求中。然后我编写了一个
LoggingMiddleware
,将该遗留id添加为日志属性

两者都很好地工作,但执行顺序错误。首先执行中间件,然后执行身份验证策略。所以我经常记录“匿名”而不是我想记录的id。我的
Startup
类有正确的顺序(我想),所以我不明白为什么它不能正常工作

Startup.cs:

    public virtual void ConfigureServices(IServiceCollection services)
    {
      var authenticationSettings = Configuration.GetSection(ConfigurationConstants.JwtSectionName).Get<AuthenticationSettings>();
      services
        .AddAuthorization(options =>
          options.AddPolicy(SecurityConstants.PolicyName,
            new AuthorizationPolicyBuilder()
              .RequireAuthenticatedUser()
              .Build()))
        .AddScoped<ISecurityQueries, SecurityQueries>()
        .AddScoped<IAuthorizationHandler, VerifyIdPolicy>()
        .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
          options.Authority = authenticationSettings.Authority;
          options.TokenValidationParameters = new TokenValidationParameters
          {
            ValidateAudience = false,
            ValidateLifetime = true,
            ValidateIssuer = true,
            ValidIssuers = authenticationSettings.Issuers.Split(';')
          };
        });

      services
        .ConfigureMvc<ContractDomainException>(Configuration)
        .ConfigureRefitClient<IAppConfigApi>(Configuration, DataContextTypes.AppConfig)
        .ConfigureServices()
        .ConfigureSwagger("Contract HTTP API")
        .ConfigureValidation(new Dictionary<string, string> {{Assembly.GetExecutingAssembly().FullName, DataContextTypes.Contract}});
    }

    public virtual void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
    {
      app
        .UseAuthentication()
        .UseCors()
        .UseMiddleware<LoggingMiddlewareTest>()
        .UseResponseCompression()
        .UseMvc();
    }

答案其实相当简单。我使用在
LoggingMiddlewareTest
之前注册的中间件

    public virtual void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
    {
      app
        .UseAuthentication()
        .UseCors()
        .UseEndpointRouting() // new
        .UseMiddleware<FetchTechnicalUserMiddleware>() // new
        .UseMiddleware<LoggingMiddlewareTest>()
        .UseResponseCompression()
        .UseMvc();
    }
如果没有
UseEndpointRouting
authorization
变量将始终为
null
。我这样做的原因是为了不必要地访问数据库,并提高不需要这些数据的调用的性能


非常感谢您为我指明了正确的方向。

authz处理程序作为
UseMvc
的一部分运行(只是为了解释原因)。如果您总是需要获取旧ID,则可以插入身份验证系统。或者,一个资源过滤器可以做日志记录-这些在authz之后和操作之前运行。为了完整起见,请注意,3.0中的情况有点不同。我认为使用策略(通过
AuthorizationHandler
)将其插入身份验证系统。这就是授权系统。这是授权策略,不是身份验证策略。概念有点模糊,但至少在3.0中,端点路由要好得多。啊,我还以为是同一个系统呢。就像第一步。验证,然后执行步骤2。授权,然后继续下一个中间件。如果你把这句话写在回答中,我会认为你解决了我的问题
    public virtual void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
    {
      app
        .UseAuthentication()
        .UseCors()
        .UseEndpointRouting() // new
        .UseMiddleware<FetchTechnicalUserMiddleware>() // new
        .UseMiddleware<LoggingMiddlewareTest>()
        .UseResponseCompression()
        .UseMvc();
    }
    public async Task InvokeAsync(HttpContext context)
    {
        var authorization = context.Features.Get<IEndpointFeature>()?.Endpoint?.Metadata.GetMetadata<AuthorizeAttribute>();
        if (authorization is PersonAuthorizeAttribute)
        {
          // fetch technical user id
        }
    }