【问题标题】:Invoke Custom AuthenticationHandler before middleware在中间件之前调用自定义 AuthenticationHandler
【发布时间】:2019-08-21 07:40:48
【问题描述】:

我有一个 ASP.NET Core WebAPI (2.2),它使用 两种 类型的身份验证:

  • JWTBearer
  • APIKey(自定义)

这是我在 Startup.cs 中配置它的方式:

services.AddAuthentication(sharedOptions =>
{
    sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddApiKeyAuthentication(options => Configuration.Bind("ApiKeyAuth", options));

services.AddAuthentication(options =>
{
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwtOptions =>
{
    jwtOptions.Authority = $"https://login.microsoftonline.com/tfp/{Configuration["AzureAdB2C:Tenant"]}/{Configuration["AzureAdB2C:Policy"]}/v2.0/";
    jwtOptions.Audience = Configuration["AzureAdB2C:ClientId"];
    jwtOptions.Events = new JwtBearerEvents
    {
        OnAuthenticationFailed = AuthenticationFailed
    };
});

我的控制器装饰有Authorize 属性,包括这两种方案。因此,我可以使用不记名令牌或通过在标头中指定 API 密钥来调用我的 Web 方法 - 效果很好。

现在我添加了一个自定义中间件,在其中执行一些特定于租户的检查。我在Configure方法中注册了中间件(在UseAuthentication之后):

// ....
app.UseAuthentication();
app.UseMiddleware<CustomMiddleware>()

现在,如果我使用 bearer 身份验证调用 REST 方法,我的 CustomMiddleware 会被经过身份验证的用户调用 - 我可以 访问声明。

如果我使用我的自定义 APIKey 身份验证调用 same REST 方法,我的CustomMiddleware 会在我的AuthenticationHandler.HandleAuthenticateAsync() 方法之前调用之前。用户经过身份验证 - 我无法访问声明(我自己在 HandleAuthenticateAsync 方法中填充声明)。

为什么在身份验证之前调用中间件?我怎样才能改变这种行为,以便在HandleAuthenticateAsync()之后调用中间件?

【问题讨论】:

  • JwtBearer 是否配置为默认认证方案?您的代码 sn-ps 未显示您如何设置默认方案。
  • @KirkLarkin 感谢您的帮助。我添加了我的确切配置。
  • 对于有问题的 REST 方法,它是否是具有 [Authorize] 属性的 MVC 操作。如果不是,那是什么?我意识到受影响的方法不止一种,但使用特定示例会更容易。
  • 我的所有控制器都使用继承自 AuthorizeAttribute 的 CustomeAuthorize 属性,并将 AuthenticationSchemes 设置为 AuthenticationSchemes = "ApiKey,Bearer";

标签: c# asp.net-core .net-core


【解决方案1】:

您需要设置一个转发默认选择器,以便在必要时将 API 密钥身份验证方案设为默认值。

这是一个例子:

services.AddAuthentication(options =>
{
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwtOptions =>
{
    jwtOptions.Authority = $"https://login.microsoftonline.com/tfp/{Configuration["AzureAdB2C:Tenant"]}/{Configuration["AzureAdB2C:Policy"]}/v2.0/";
    jwtOptions.Audience = Configuration["AzureAdB2C:ClientId"];
    jwtOptions.Events = new JwtBearerEvents
    {
        OnAuthenticationFailed = AuthenticationFailed
    };
    jwtOptions.ForwardDefaultSelector = ctx =>
    {
        if (ctx.Request.Headers.TryGetValue("Api-Key", out var headerValues))
        {
            return "ApiKeyAuth";
        }

        return null;
    };
})
.AddApiKeyAuthentication(options => Configuration.Bind("ApiKeyAuth", options));

我做了一些猜测来构建选择器, 但基本上如果应该使用另一个方案,它需要返回另一个方案的名称, 否则为 null。

在示例中,它检查请求中是否包含“Api-Key”标头, 如果是,则返回“ApiKeyAuth”,这是 API 密钥方案的名称。 如果它们不同,请将它们交换为您的值。

如果在两种方案中都使用了 Authorization: Bearer xyz 标头, 您需要检查选择器中的标题内容才能做出决定。

【讨论】:

    猜你喜欢
    • 2020-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-10
    • 2020-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多