根据 url 参数选择身份方案

Chose identity scheme based on url parameter

我正在尝试根据请求参数选择openId授权方案。

我添加了两个 openIdConnect 模式:

.AddOpenIdConnect("abc", abcHandler)
.AddOpenIdConnect("def", defHandler);

一开始我覆盖了整个授权中间件并挑战:

if (authorizeResult.Challenged)
{
    if (valueFromQueryString.Contains("abc"))
    {
        await context.ChallengeAsync("abc");
    }
    else if (valueFromQueryString.Contains("def"))
    {
        await context.ChallengeAsync("def");
    }
}

但后来我注意到有一些政策,所以尝试使用这些政策。我创建了我的要求,然后添加了两个具有如下模式的策略:

services.AddAuthorization(options =>
    {
        options.AddPolicy("abc", policy =>
            {
                policy.AuthenticationSchemes.Add("abc");
                policy.Requirements.Add(new TenantSpecificRequirement("abc"));
                policy.RequireAuthenticatedUser();
             });
        options.AddPolicy("def", policy =>
            {
                policy.AuthenticationSchemes.Add("def");
                policy.Requirements.Add(new TenantSpecificRequirement("def"));
                policy.RequireAuthenticatedUser();
            });
    });

我意识到策略必须像这样绑定到控制器:

[Authorize(Policy = "abc")]
[Authorize(Policy = "def")]

这完全不是我需要的。现在最好的办法是根据 url 将策略动态分配给控制器,但似乎不可能,因为应用程序启动时不会添加控制器过滤器。

那还有没有别的办法呢?

好的,我通过覆盖 AuthenticationSchemeProvider

找到了解决方案
public class SubdomainAuthenticationSchemeProvider : AuthenticationSchemeProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CustomAuthenticationSchemeProvider(
        IHttpContextAccessor httpContextAccessor,
        IOptions<AuthenticationOptions> options)
        : base(options)
    {
        this._httpContextAccessor = httpContextAccessor;
    }

    private Task<AuthenticationScheme> GetRequestSchemeAsync()
    {
        // Get the subdomain for the host the request came from. Assumes no WWW in the string.
        var subdomainName = _httpContextAccessor.HttpContext.Request.Host.Host.Split(new char[] { '.' })[0];

        return GetSchemeAsync(subdomainName);
    }

    public override async Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync() => await GetRequestSchemeAsync() ;

    public override async Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync() =>
        await GetRequestSchemeAsync() ??
        await base.GetDefaultChallengeSchemeAsync();

    public override async Task<AuthenticationScheme> GetDefaultForbidSchemeAsync() =>
        await GetRequestSchemeAsync() ??
        await base.GetDefaultForbidSchemeAsync();

    public override async Task<AuthenticationScheme> GetDefaultSignInSchemeAsync() =>
        await GetRequestSchemeAsync() ??
        await base.GetDefaultSignInSchemeAsync();

    public override async Task<AuthenticationScheme> GetDefaultSignOutSchemeAsync() =>
        await GetRequestSchemeAsync() ??
        await base.GetDefaultSignOutSchemeAsync();

}

在此之后,将其添加到 ConfigureServices 方法中

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IAuthenticationSchemeProvider, SubdomainAuthenticationSchemeProvider>();