使用从 JavaScript 客户端收到的令牌在服务器上创建社交连接

Use token received from JavaScript client to create a social connection on the server

我有一个使用 PHP/JavaScript 的网页,可以在客户端成功执行 Google 登录过程。然后我想将获得的令牌转发到使用 Spring-Social 创建社交连接的后端,并能够调用应用程序已获得授权的 APIs。 我设法在 Facebook (OAUTH2) 和 Twitter (OAUTH1) 上都做到了这一点,它们都完美地工作,但是对于 Google,我在尝试创建连接时总是收到 401 响应。 服务器中的代码是这样的:

AccessGrant accessGrant = new AccessGrant(accessToken);
connection = ((OAuth2ConnectionFactory<?>) connectionFactory).createConnection(accessGrant);

客户端的代码是这样的:

    function onSignIn(googleUser) {
        var profile = googleUser.getBasicProfile();
        console.log('ID: ' + profile.getId());
        console.log('Name: ' + profile.getName());
        console.log('Email: ' + profile.getEmail());

        var access_token = googleUser.getAuthResponse().id_token;
        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'http://localhost/signin/google');
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.onload = function() {
            console.log('Signed in as: ' + xhr.responseText);
            console.log('access_token=' + access_token);
        };
        xhr.send('access_token=' + access_token);

    }

后者的大部分是从 Google 文档中复制的关于如何使用后端服务器进行身份验证的文档:https://developers.google.com/identity/sign-in/web/backend-auth

我追踪了 spring-social-google 内部的调用,它们导致对 https://www.googleapis.com/oauth2/v2/userinfo 的 REST 调用,即回复 401 和以下 JSON:

{
    "error": {
        "errors": [{
            "domain": "global",
            "reason": "authError",
            "message": "Invalid Credentials",
            "locationType": "header",
            "location": "Authorization"
        }],
        "code": 401,
        "message": "Invalid Credentials"
    }
}

我自己尝试调用相同的 REST API,我也得到了相同的响应,所以这似乎不是 spring-social-[=52 的问题=] 正如我在其他一些帖子中读到的那样,没有正确发送令牌。

我认为这个问题与 JavaScript API 给我一个 "id_token" 而 REST API 期待一个 "access_token"。但是,我没有找到一种方法来获取访问令牌作为与 id_token 分开的东西,并且 Google 文档确实将 id_token 发送到后端。 "access_token" 属性 在 googleUser.getAuthResponse() 中使用的 "id_token" 属性 旁边有一个 "access_token" 属性 但它返回未定义。 这个文档当然不是针对 spring-social 所以我并不是说它不正确,我只是想知道实现这个的正确方法是什么。

spring-无法处理 id_token 是社会的错吗?

我没有看到一些明确的方法来获得 access_token 是我的错吗?

无论如何,我觉得我有点接近了,但解决方案似乎仍然无法掌握。

谢谢!

嗯,我找到了。看来把整件事都写下来真的是脑子里有什么东西绊倒了...

问题实际上是 id_token 不能代替 access_token。根据我的口味,Google 文档在他们展示的示例中可能对此更明确一些,但他们最终在 https://developers.google.com/identity/sign-in/web/reference

的实际客户参考中对其进行了解释

关键是 getAuthResponse() 的布尔参数,它是可选的,默认为 false。来自文档:

includeAuthorizationData Optional: A boolean that specifies whether to always return an access token and scopes. By default, the access token and requested scopes are not returned when fetch_basic_profile is true (the default value) and no additional scopes are requested.

通过在我的 JS 中将其设置为 true,填充了以前未定义的 access_token 字段,使用此令牌可以访问 /oauth2/v2/userinfo 端点和 spring-social-google 可以像其他提供商一样正确地创建连接。

我希望这至少对其他人有所帮助。