【问题标题】:Get a new access_token from IdentityServer4 when validated Google Id Token from SPA从 SPA 验证 Google Id 令牌时从 IdentityServer4 获取新的 access_token
【发布时间】:2020-11-30 11:44:59
【问题描述】:

我正在使用 ASP.NET Identity 创建 IdentityServer4 身份验证,用于 React SPA 和具有基于策略的授权的 ASP.NET Core Web API。

Take a look at this flow diagram as I am not yet able to embed images directly into the question.

所以基本上我到目前为止所做的,

  1. 成功登录 Google 后,React SPA 将具有“使用 Google 登录”(“react-google-login”库)
  2. 收到包含 IdToken 和其他内容的“tokenObj”响应
  3. POST 请求,使用 Id 令牌 和一些额外的声明字段,从 React SPAIdentityServer4 端点
  4. 使用 Google 客户端库方法 Google.Apis.Auth.GoogleJsonWebSignature.ValidateAsync 从 IdentityServer4 控制器端点验证 IdToken
  5. IdToken 验证成功后,使用 ASP.NET Identity UserManager 方法创建/获取用户,并且,
  6. 此外,在 POST 请求中传递的自定义声明会为该用户添加到数据库中

我现在想做什么

  1. 从 IdentityServer4 获取“access_token”,将其传递到该 POST 请求的成功响应中。

注意:不要将 Google 提供的 access_token 传递给 React SPA。想 将 IdentityServer4 颁发的 access_token 传递给 SPA。并且访问令牌在解码时应包含该自定义声明,以进一步处理基于策略的 在另一个 API 中进行授权。 我也知道 ProfileService 是用来传递 IdentityServer4 发出的访问令牌里面的自定义声明,所以 ProfileService 我已经实现了。

所以问题主要集中在使用Google IdToken验证用户后如何通过IdentityServer4颁发的新access_token

最小的工作示例


  public class ExternalLoginModel
     {
        public string IdToken { get; set; }
        public string UserRole { get; set; }
     }
[Route("api/[controller]")]
[ApiController]
public class ExternalAuthController : ControllerBase
{
   [HttpPost]
   [Route("google")]
   public async Task<IActionResult> AuthenticateGoogleSignin(ExternalLoginModel externalLoginModel)
        {
            Payload payload;
            var provider = "google";
            try
            {
                // currently no need to validate
                var validationSettings = new ValidationSettings
                { Audience = new[] { "YOUR_CLIENT_ID" } };
                payload = await GoogleJsonWebSignature.ValidateAsync(
                    externalLoginModel.IdToken, validationSettings);
                 // create custom claims and store claims for the user found from Google IdToken
                 // storing custom claims passed in request if user is created.
                var userRole = externalLoginModel.UserRole;
                var user = await GetOrCreateExternalLoginUser("google", 
                                                                    payload.Subject,
                                                                    payload.Email,
                                                                    userRole);

                return Ok(new
                {
                    access_token = "want_to_give_identity_server4_issued_access_token"
                });
            }
            catch
            {
                // Invalid token
            }
            return BadRequest();
        }
}

【问题讨论】:

标签: asp.net-core asp.net-web-api asp.net-identity identityserver4


【解决方案1】:

我认为你把它弄得比它必须要复杂的多。

我认为更好的方法是让您的 SPA 应用程序要求您的后端(ASP.NET 身份)要求 IdentityServer 对用户进行身份验证。然后使用外部身份验证,IdentityServer 将要求用户通过 Google 进行身份验证。

通过这样做,IdentityServer 和 Google 将直接相互交谈。身份验证后,您将从 IdentityServer 取回令牌并将其发送回 ASP.NET Identity。使用这些令牌,可以将适当的会话 cookie 发布到您的 SPA 应用程序。

这是一种更安全的方法,可以避免 SPA 应用程序处理此问题。

要实现外部身份验证,请从以下几个起点开始:

除此之外,我认为这个问题可能需要进一步澄清?也许您的设置图片会有所帮助。

关于你的图片,你不应该直接从 React 转到 Google,而是通过 IdentityServer 然后 Google,就像这张图片:

react 和 Google 不应该直接交互。 IdentityServer 保护您的应用免受 Google 的攻击。

【讨论】:

  • 基本上,我有两个 SPA,一个用于 ClientAdmin,另一个用于 EndUsers。当任何用户使用 Google“登录”从各自的 SPA 注册时,我想存储用户的自定义声明,如“user_role”例如“clientAdmin”或“paidUser”。并且在响应中需要来自 IdentityServer4 的 access_token 以及特定 SPA 用户的这些自定义声明。那么关于如何实现这一目标的任何建议?
  • 感谢您提供的外部提供商示例链接,我已经浏览过,并且在他们的解决方案中,他们正在使用自定义授权验证器。但它并没有解决我将自定义声明从 ReactSPA 传递到 IdentityServer4 的一个问题。那么我们有什么方法可以传递自定义声明并将声明存储到 DB 并将它们放入 IdentityServer4 颁发的访问令牌中,同时使用自定义授予,例如'外部'?
  • 我在上面澄清了我的答案,希望这个答案可以接受
  • 我正在学习/研究您提供的流程。在这个流程中,我可以使用 location.href 从我的 SPA 调用或重定向到 IdentityServer 端点“ExternalLoginChallenge”。如果这是正确的方法,请纠正我?执行挑战。然后,我被重定向到 Google 登录屏幕,在成功登录后,收到了对 IdentityServer“ExternalLoginCallback”GET 端点的回调,其中“returnUrl”指向我的 SPA,现在可以使用 ASP NET Identity 创建/查找用户.所以从这里开始,问题是我将如何获得 IdentityServer 访问令牌并重定向到我的 SPA?
  • 不,您从不直接调用 ExternalController(当然可以),但通常它是在 Accounts\Login 视图中生成的链接。然后你就会知道你得到的所有细节都是正确的。
【解决方案2】:

您必须执行以下步骤才能获得用户的海关索赔:-

  1. 将自定义声明添加到 IdentityResource 列表中。
  2. 针对用户设置索赔。
  3. 在允许的范围列表中添加针对客户端的声明 必须发行哪个令牌。
  4. 从身份服务器获取访问令牌后,使用 然后您可以调用用户信息端点GET /connect/userinfo 获取该列表的令牌 为用户设置的声明。

【讨论】:

  • 已经为 ResourceOwnerPassword 授权类型执行了存储和获取自定义声明的步骤,并使用 IProfileService 的实现直接在 IdentityServer4 提供的访问令牌中获取了自定义声明。所以基本上我需要一种方法来获取来自 IdentityServer4 的自定义声明的访问令牌,用于谷歌、Facebook 等外部提供商。
  • 对不起,我有点困惑,如果我错了,请纠正我 - 所以要求是用户的自定义声明应该包含在身份服务器生成的访问令牌中?
  • 我添加了一个图表链接以使其更清晰。并对场景的描述进行了一些修改。拜托,你能看看吗?
  • 如果我错了,请纠正我 - 从谷歌成功登录后,您将 id_token 和 customuserroleclaim 一起传递给身份服务器,然后您将针对用户的声明存储在 sql db 中,现在您将想要在身份服务器成功验证 id_token 后在访问令牌中传递角色声明?
  • 从 google 成功登录后,将 id_token 与 customuserroleclaim 一起传递给 IdentityServer,在身份服务器从 google 令牌端点成功验证 id_token 时,接收用户信息,现在将声明存储在 MSSQL 中db 针对使用 ASP NET 标识的用户。现在想将 IdentityServer 为该用户提供的访问令牌传递给我的 SPA?这样我就可以通过某些策略在另一个 Web API 上授权该用户
猜你喜欢
  • 2021-01-23
  • 2018-12-12
  • 2016-12-27
  • 2021-09-07
  • 2015-07-15
  • 2017-11-19
  • 1970-01-01
  • 2019-05-15
  • 2019-02-25
相关资源
最近更新 更多