多种身份验证方案ASPNET Core 3

时间:2020-06-26 23:03:03

标签: c# asp.net-core authentication jwt azure-ad-b2c

请参阅下面的更新

我正在使用Azure AD B2C,希望用户能够通过我的Web应用程序登录,并能够利用JWT承载令牌并从移动应用程序调用Web API方法。

我可以使任一种身份验证方案都能自行工作。例如,在我的startup.cs中,我可以执行以下操作:

        services
            .AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
            .AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options));

可以正常工作(用户可以登录网站,但是JWT不起作用)。

或者,我可以改用以下代码,然后只有JWT承载令牌才能工作:

        services
            .AddAuthentication(AzureADB2CDefaults.JwtBearerAuthenticationScheme)
            .AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));

如果我要工作,可以执行以下操作(在https://stackoverflow.com/a/49706390的帮助下)

        services
            .AddAuthentication()
            .AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options))
            .AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));

        services.AddAuthorization(options =>
        {
            options.DefaultPolicy = new AuthorizationPolicyBuilder()
                                    .RequireAuthenticatedUser()
                                    .AddAuthenticationSchemes(AzureADB2CDefaults.AuthenticationScheme, AzureADB2CDefaults.JwtBearerAuthenticationScheme)
                                    .Build();
        }

现在两者都可以工作。 (编辑:实际上,它们不能完全正常工作)

但是,我也有以下代码:

        app.UseAuthentication();
        app.UseMiddleware<MyAfterAuthenticatedMiddleware>();
        app.UseAuthorization();

问题是,当我使用两种身份验证的组合时,当我的中间件代码运行时,我的用户未经过身份验证(在中间件代码中)并且没有声明等,但是稍后在管道中获取它们。

>

这是怎么回事?以及如何解决?

似乎,当我没有指定默认的身份验证方案时-为了具有多个方案-直到管道中的授权步骤,身份验证才发生​​。

我需要我的中间件在身份验证之后和授权之前运行。 如何通过多种身份验证方案实现这一目标?

更新-已解决!但是必须有更好的方法!??

首先,对于那些创建.NET安全性东西的人,我要表示敬意。这很重要,也很困难。 但是我确实认为可能还有很多改进的空间。

大多数开发人员不得不在需要时涉足安全性,然后再回到他们的“常规”工作中。除非您每天都在使用它,否则很难保持领先地位。又改变了。

这必须是常见的情况:我希望我的用户能够登录到我的网站并与各种Web API方法进行交互。我希望他们也能够通过其他方式(例如移动应用程序)访问这些相同的API方法,而我将使用JWT令牌或等效方法。

这应该很容易。

但是,我将自己束之高阁,为此创建了处理程序并为此制定了策略。一件事会起作用,但另一件事却不会。然后,当我认为事情是对的时,我发现了一些挑战和禁止逻辑无法按预期工作

内置的Authorization中间件具有进行身份验证的能力-这是我失败的早期方法之一,却发现它没有完全起作用-并给我造成了其他问题,如前所述以上。

我认为,身份验证应该在授权过程中发生。身份验证应该在预期的地方进行-在身份验证中间件中。 (我猜想它是在授权中添加的,目的是要解决几年前出现的其他问题-也许今天仍然存在)

无论如何-这是我终于可以工作的方式。它可能更干净,更流畅,更灵活,但是可以满足我的需求。而且,它比我见过的其他任何东西都更少。但是,有没有更好的内置类可以为我做到这一点?

我的新问题是:是否有比下面所述的方法更好的方法来完成此操作?。很难相信这是最好的方法。

在Startup.ConfigureServices中,我现在具有以下内容:

services
   .AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
   .AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options))
   .AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));

然后我也有:

services.AddHttpContextAccessor();
services.AddSingleton<IAuthenticationSchemeProvider, MyAuthenticationSchemeProvider>();

最后,我有一堂新课:

public class MyAuthenticationSchemeProvider : AuthenticationSchemeProvider
{
    public MyAuthenticationSchemeProvider(IOptions<AuthenticationOptions> options, IHttpContextAccessor httpContextAccessor) : base(options)
    {
        HttpContextAccessor = httpContextAccessor;
    }

    protected MyAuthenticationSchemeProvider(IOptions<AuthenticationOptions> options, IDictionary<string, AuthenticationScheme> schemes, IHttpContextAccessor httpContextAccessor) : base(options, schemes)
    {
        HttpContextAccessor = httpContextAccessor;
    }

    private IHttpContextAccessor HttpContextAccessor { get; }

    private bool IsBearerRequest()
    {
        var httpContext = HttpContextAccessor.HttpContext;
        return httpContext.Request.Headers.ContainsKey("Authorization")
                && httpContext.Request.Headers["Authorization"].Any(x => x.ToLower().Contains("bearer"));
    }

    public async Task<AuthenticationScheme> GetMySchemeAsync()
    {
        return IsBearerRequest()
            ? await GetSchemeAsync(AzureADB2CDefaults.BearerAuthenticationScheme)
            : await base.GetDefaultAuthenticateSchemeAsync();
    }

    public override async Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync()
    {
        return await GetMySchemeAsync();
    }

    public override Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync()
    {
        return GetMySchemeAsync();
    }

    public override Task<AuthenticationScheme> GetDefaultForbidSchemeAsync()
    {
        return GetMySchemeAsync();
    }
}

现在,我可以同时使用两种身份验证,质询和禁止工作。为什么没有内置的类可以在身份验证方案之间进行切换?为什么授权中间件尝试使用多种方案进行身份验证(我说它根本不应该这样做),而不是身份验证中间件?

现在,这里是任何其他遇到类似问题的人。

0 个答案:

没有答案