【问题标题】:API Authentication using multiple Authentication Providers使用多个身份验证提供程序的 API 身份验证
【发布时间】:2021-02-28 04:53:56
【问题描述】:

这个主题感觉应该更好地记录下来 - 或者我在搜索时使用了错误的术语。

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

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

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

我找到了很多关于从一个离散的、已知的授权提供者验证令牌的文档,但关于使用多个提供者的文档却很少。由于所有应用程序都可以让您选择 Oauth2 登录方式(其中包括 StackOverflow),我认为这将是一个更常见的问题。

我错过了什么!?

【问题讨论】:

  • 您是否尝试过添加此处提到的提供程序? docs.microsoft.com/en-us/aspnet/core/security/authentication/…
  • 是的,我尝试过以这种方式添加一对,但无法使其工作。该文档是针对“Web 应用程序”而不是后端 API 的(不确定这是否会有所不同(。我认为它必须不仅仅是链接 addProvider 方法。本文档中的细节很少。如果我要让它工作,我将如何找到用户信息?

标签: asp.net-core authentication oauth-2.0


【解决方案1】:

似乎解决这种情况的正确方法是构建一个自定义身份验证处理程序,如此处所述:https://referbruv.com/blog/posts/implementing-custom-authentication-scheme-and-handler-in-aspnet-core-3x

在这个身份验证处理程序中,我可以解码令牌,断言颁发者是白名单的成员验证访问令牌使用颁发者的公钥,并使用令牌的其余部分构建身份我需要进一步授权。

至少现在我对要搜索的内容有了更好的了解,而且我并没有完全重新发明身份验证机制!

【讨论】:

  • 是的 - 当您处理 JWT 时,这是一种常见的方法。您可能会发现来自 Google 和 Facebook 的访问令牌是不透明的字符串,而不是 JWT - 值得先检查一下。
  • 好点。但到目前为止,我一直在处理的令牌(来自 ADFS、Okta 和 Google ID 令牌)似乎都是 JWT,上面有足够的信息。
【解决方案2】:

您需要在 API 中以一致的方式识别用户,然后根据身份 + 范围授权请求。

正如您所发现的,当使用许多不同的令牌提供者时,这将非常困难。他们的访问令牌并非专为您在自己的 API 中使用而设计的。

更好的机制是仅使用来自您自己的授权服务器的令牌,以支持不同的登录方法,同时让您的代码处于控制之中。我的Federated Logins 博文有更多信息。

【讨论】:

  • 所以你证实了我的想法,这不是一个简单的问题。我一直在想一个解决方案是制作我自己的 /auth 端点,我可以向其提交这些 3rd 方访问令牌,并发出我自己的 jwt,它可以在整个 API 的其余部分中使用。但那时我觉得我想太多了。听起来我不是?
  • 不幸的是,这并不简单 - 如果您插入授权服务器,它将为您完成验证第三方令牌的工作。作为一个短期选项,UI 可以在 API 调用期间告诉 API 令牌提供者 - 可能通过自定义标头。更深层次的问题是 API 可能无法从第三方令牌中获取所需的声明。
【解决方案3】:

事实证明,这毕竟是我想多了。

由于我正在处理 API 后端,我需要做的就是验证 IDP Bearer 令牌,而不是创建它们。最后,我能够使用以下简单代码验证 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")]

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 2018-10-31
    • 2017-01-14
    • 1970-01-01
    • 2012-02-18
    相关资源
    最近更新 更多