为什么我的身份验证中间件在未提供令牌时将请求传递给授权过滤器?
Why does my authentication middleware pass a request to the authorization filter when no token is supplied?
我有一个 .NET Core 1.1 Web API,它使用 JWT 身份验证中间件和自定义授权过滤器。它们是这样定义的:
services.AddSingleton<IAuthorizationRequirement, MercuryEndpointAuthorizationHandler>();
services.AddSingleton<IEndpointAuthorizeDictionary, EndpointRights>();
services.AddSingleton<IAuthorizationHandler, MercuryEndpointAuthorizationHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy("AuthorizeMercuryEndpoint", policy =>
{
policy.AddRequirements(services.BuildServiceProvider().GetService<IAuthorizationRequirement>());
});
});
和
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters,
Events = new JwtBearerEvents()
{
OnMessageReceived = async (context) =>
{
Debug.WriteLine("====> JWT Message received");
},
OnTokenValidated = async (context) =>
{
Debug.WriteLine("====> JWT token validated");
context.HttpContext.Items["JwtTokenIsValid"] = true;
},
OnAuthenticationFailed = async (context) =>
{
Debug.WriteLine("====> JWT token failed auth");
context.HttpContext.Items["JwtTokenIsValid"] = false;
if ((AuthenticationType.IdServer & authTypes) != 0)
context.SkipToNextMiddleware();
}
}
});
当我调用受 [Authorize("AuthorizeMercuryEndpoint")]
保护的端点和有效的 JWT 令牌时,调用按预期成功,我看到进程编写了以下调试:
====> JWT Message received
====> JWT token validated
====> Request authorized (when the auth filter succeeds)
但是,如果我不传递令牌,JWT 中间件似乎会直接将请求传递给授权过滤器而不尝试进行身份验证 - OnTokenValidated
和 OnAuthenticationFailed
都不会被调用,并且在授权时失败(因为没有经过身份验证的身份)管道终止。
这是一个问题,因为如果 JWT 令牌验证未通过初始身份验证,我想将请求传递给第二个身份验证中间件。
有谁知道推荐的方法是什么?
仅当 JWT 中间件在 HTTP 请求中找到令牌时,它才会应用验证部分,您可以 see here。
Authorize
属性现在包含一个 ActiveAuthenticationSchemes
属性,它定义将执行哪些身份验证方案以尝试对用户进行身份验证。这样做的好处是您现在可以删除 JWT 中间件选项中的 AutomaticAuthenticate
,它会在需要时延迟执行 - 例如,如果用户点击不需要身份验证的操作,它就不会执行。
不过,您可能不喜欢的一件事是 MVC 不会像您可以的那样在身份验证方案成功后停止 see here。如果这是 trade-off 你愿意接受的,我认为这是一个不错的选择。
我有一个 .NET Core 1.1 Web API,它使用 JWT 身份验证中间件和自定义授权过滤器。它们是这样定义的:
services.AddSingleton<IAuthorizationRequirement, MercuryEndpointAuthorizationHandler>();
services.AddSingleton<IEndpointAuthorizeDictionary, EndpointRights>();
services.AddSingleton<IAuthorizationHandler, MercuryEndpointAuthorizationHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy("AuthorizeMercuryEndpoint", policy =>
{
policy.AddRequirements(services.BuildServiceProvider().GetService<IAuthorizationRequirement>());
});
});
和
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters,
Events = new JwtBearerEvents()
{
OnMessageReceived = async (context) =>
{
Debug.WriteLine("====> JWT Message received");
},
OnTokenValidated = async (context) =>
{
Debug.WriteLine("====> JWT token validated");
context.HttpContext.Items["JwtTokenIsValid"] = true;
},
OnAuthenticationFailed = async (context) =>
{
Debug.WriteLine("====> JWT token failed auth");
context.HttpContext.Items["JwtTokenIsValid"] = false;
if ((AuthenticationType.IdServer & authTypes) != 0)
context.SkipToNextMiddleware();
}
}
});
当我调用受 [Authorize("AuthorizeMercuryEndpoint")]
保护的端点和有效的 JWT 令牌时,调用按预期成功,我看到进程编写了以下调试:
====> JWT Message received
====> JWT token validated
====> Request authorized (when the auth filter succeeds)
但是,如果我不传递令牌,JWT 中间件似乎会直接将请求传递给授权过滤器而不尝试进行身份验证 - OnTokenValidated
和 OnAuthenticationFailed
都不会被调用,并且在授权时失败(因为没有经过身份验证的身份)管道终止。
这是一个问题,因为如果 JWT 令牌验证未通过初始身份验证,我想将请求传递给第二个身份验证中间件。
有谁知道推荐的方法是什么?
仅当 JWT 中间件在 HTTP 请求中找到令牌时,它才会应用验证部分,您可以 see here。
Authorize
属性现在包含一个 ActiveAuthenticationSchemes
属性,它定义将执行哪些身份验证方案以尝试对用户进行身份验证。这样做的好处是您现在可以删除 JWT 中间件选项中的 AutomaticAuthenticate
,它会在需要时延迟执行 - 例如,如果用户点击不需要身份验证的操作,它就不会执行。
不过,您可能不喜欢的一件事是 MVC 不会像您可以的那样在身份验证方案成功后停止 see here。如果这是 trade-off 你愿意接受的,我认为这是一个不错的选择。