Warm tip: This article is reproduced from serverfault.com, please click

asp.net core-使用多个身份验证提供程序的API身份验证

(asp.net core - API Authentication using multiple Authentication Providers)

发布于 2020-11-16 23:49:42

该主题是一个应该对其进行更好地记录的主题-也许我在搜索时使用了错误的术语。

  • 我有几个使用各种Oauth2登录名(即Okta,Facebook,Google)进行身份验证并生成访问令牌的SPA应用程序。

  • 这些应用程序都访问通用的API后端(asp.net核心)。对API的所有请求都将Oauth2访问令牌附加为授权标头。

如何配置此单个后端API,以在不事先知道附加了哪个访问令牌的情况下验证来自各种提供商之一的这些访问令牌,并解码可用于进一步授权目的的用户电子邮件地址?

我发现了很多有关验证来自离散的,已知的授权提供程序的令牌的文档,但很少涉及使用多个提供程序的文档。有了所有可供选择的Oauth2登录(其中包括StackOverflow)的应用程序,我认为这将是一个更常见的问题。

我想念什么!?

Questioner
Brent
Viewed
11
Brent 2020-11-30 23:24:57

事实证明,我毕竟对此思考过多。

由于我正在处理API后端,因此我要做的就是验证IDP承载令牌,而不是创建它们。最后,我能够使用以下简单代码验证3个ID提供程序:

services.AddAuthentication(OKTA_SCHEME)
                .AddJwtBearer(ADFS_SCHEME, options =>
                {
                    options.Authority = adfsConfig.authority;
                    options.Authority = adfsConfig.authority;
                })
                .AddJwtBearer(GOOGLE_SCHEME, jwt => jwt.UseGoogle(
                    clientId: googleConfig.clientId
                ))
                .AddJwtBearer(OKTA_SCHEME, options =>
                {
                    options.Authority = oktaConfig.authority;
                    options.Audience = oktaConfig.audience;
                });

请注意,这需要安装一个附加的nuget软件包以简化对Google令牌的验证,该令牌似乎不遵循以下标准:Hellang.Authentication.JwtBearer.Google。

此时,我可以使用以下属性进行授权:

[Authorize(AuthorizationSchemes = OKTA_SCHEME)]

...或根据方案制定政策。

第二部分问题是将我的各种登录信息链接到本地​​数据库中的用户,最终我使用了自定义IClaimsTransformation进行了该操作,该IClaimsTransformation使用填充到ClaimsPrincipal中的信息来查找数据库中的用户,并添加“雇员”角色声明,如果找到了。

public class EmployeeClaims : IClaimsTransformation
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        if (!principal.HasClaim(a => a.Type == "EmployeeNumber"))
        {
            Employee employee = lookupEmployee(principal);
            if (employee != null)
            {
                ClaimsIdentity id = new ClaimsIdentity();
                id.AddClaim(new Claim(ClaimTypes.Role, "Employee"));
                id.AddClaim(new Claim("EmployeeNumber", employee.EmployeeNumber.ToString()));
                principal.AddIdentity(id);
            }
        }
        return Task.FromResult(principal);
    }
    private Employee lookupEmployee(ClaimsPrincipal principal) {
        string issuer = principal.Claims.Single(a => a.Type == "iss").Value;
        if (issuer.Contains("google.com"))
        ...
    }
}

然后通过以下方式注册此IClaimsTransformation:

services.AddScoped<IClaimsTransformation, EmployeeClaims>();

现在,我可以另外授权员工:

[Authorize(Roles = "Employee")]