在中间件之前调用自定义AuthenticationHandler

时间:2019-08-21 07:40:48

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

我有一个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密钥来调用我的网络方法-很好。

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

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

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

如果我使用自定义的 APIKey 身份验证调用相同 REST方法,我的CustomMiddleware在我的{{1 }} 方法。用户未经身份验证-我无法访问声明(我在AuthenticationHandler.HandleAuthenticateAsync()方法中填充了声明)。

为什么在身份验证之前调用中间件?如何更改行为,以使中间件在HandleAuthenticateAsync之后被称为之后

1 个答案:

答案 0 :(得分: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”标头, 如果是,则返回“ API密钥方案”的名称“ ApiKeyAuth”。 如果它们不同,则将其交换为您的值。

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