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