从 SPA 验证 Google Id 令牌后,从 IdentityServer4 获取新的 access_token

Get a new access_token from IdentityServer4 when validated Google Id Token from SPA

我正在使用 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. React SPA 将在成功 Google 登录
  2. 时具有“使用 Google 登录”(“react-google-login” lib)
  3. 收到带有“tokenObj”的响应,其中包含 IdToken 和其他内容
  4. POST 请求,使用 Id 令牌 和一些额外的声明字段,从 React SPAIdentityServer4端点
  5. 使用 Google 客户端库方法 Google.Apis.Auth.GoogleJsonWebSignature.ValidateAsync
  6. 从 IdentityServer4 控制器端点验证 IdToken
  7. IdToken 验证成功后 Create/Get 用户使用 ASP.NET Identity UserManager 方法,
  8. 此外,在 POST 请求中传递的自定义声明已为该用户添加到数据库中

我现在想做什么,

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

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

所以问题主要集中在IdentityServer4验证用户使用Google IdToken.

最小工作示例


  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();
        }
}

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

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

进行身份验证

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

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

要获得外部身份验证,这里有几个起点:

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

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

React 和 Google 不应直接交互。 IdentityServer 保护您的应用程序免受 Google.

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

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