首页 > 解决方案 > 从 SPA 验证 Google Id 令牌时从 IdentityServer4 获取新的 access_token

问题描述

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

看一下这个流程图,因为我还不能将图像直接嵌入到问题中。

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

  1. React SPA 将在 Google 成功登录时具有“使用 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-coreasp.net-web-apiasp.net-identityidentityserver4

解决方案


我认为你让这变得比它必须的更复杂。

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

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

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

为了使外部身份验证到位,这里有几个起点:

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

关于您的图片,您不应该直接从 React 转到 Google,而是通过 IdentityServer 然后 Google,如下图所示:

在此处输入图像描述

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


推荐阅读