0

我有一个使用 PHP/JavaScript 的网页,可以在客户端成功执行 Google 登录过程。然后我想将获得的令牌转发到使用 Spring-Social 创建社交连接并能够调用应用程序已授权的 API 的后端。我设法通过 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-google 没有正确发送令牌的问题,正如我在其他一些帖子中所读到的那样。

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

由于无法处理 id_token,spring-social 是否有过错?

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

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

谢谢!

4

1 回答 1

0

嗯,我找到了。似乎把整件事写下来真的让我脑子里有些东西……

问题实际上是 id_token 不能代替 access_token。根据我的口味,谷歌文档在他们展示的示例中可能会更明确一点,但他们最终会在https://developers.google.com/identity/sign-in/web/的实际客户参考中解释它参考

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

includeAuthorizationData 可选:一个布尔值,指定是否始终返回访问令牌和范围。默认情况下,当 fetch_basic_profile 为 true(默认值)并且不请求其他范围时,不会返回访问令牌和请求的范围。

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

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

于 2018-06-01T18:53:45.130 回答