谷歌 API 的 refresh_token 为 null,如何刷新访问令牌

7

我使用HWIO Bundle进行谷歌API的操作,但当我从谷歌收到响应时,refreshToken = null。为什么会这样?如何刷新token?

oAuthToken = {HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken} [11]
accessToken = "ya29.Ci8lA1JTu9CB81dOFy-nzszViRgCI2CvvKVrCd0Lq-8I0QR_dIrl-_7RccdGt1Islg"
rawToken = {array} [4]
 access_token = "ya29.Ci8lA1JTu9CB81dOFy-nzszViRgCI2CvvKVrCd0Lq-8I0QR_dIrl-_7RccdGt1Islg"
 token_type = "Bearer"
 expires_in = 3578
id_token = "xxxxx"
refreshToken = null
expiresIn = 3578
createdAt = 1468957368
tokenSecret = null
resourceOwnerName = null

因为在google/apiclient中,函数中的"version": "1.1.7"需要刷新令牌(refresh_token)。

 public function getRefreshToken()
 {
  if (array_key_exists('refresh_token', $this->token)) {
    return $this->token['refresh_token'];
  } else {
    return null;
  }
 }

这是我的访问令牌

{"access_token":"ya29.Ci8lA1JTu9CB81dOFy-nzszViRgCI2CvvKVrCd0Lq-8I0QR_dIrl-_7RccdGt1Islg","token_type":"Bearer","expires_in":3578,"id_token":"xxxx","created":1468957368}

我没有刷新令牌,因为从Google获取到的refreshToken = null,或者需要使用refresh token键设置为null,或者这无关紧要?

    $isExpired = $client->isAccessTokenExpired(); // true (bool Returns True if the access_token is expired.)
    $refresh = $client->getRefreshToken(); //null because not gahe refresh token 

    $client->getGoogleClient()->setAccessType ("offline"); //some  recomendation
    $client->getGoogleClient()->setApprovalPrompt ("force"); //some recomendation

    $isAgainExpired = $client->isAccessTokenExpired(); // still true (expired)

仍然存在异常 - OAuth 2.0访问令牌已过期,且没有可用的刷新令牌。自动批准的响应不返回刷新令牌。

如何刷新令牌以及如何使用令牌获取刷新令牌?

我尝试了

  • In my code too $client = new Google_Client() but in wrapper, in constructor.
  • I get access token from HWIO bundle:

    hwi_oauth:
    connect:
      account_connector: app.provider.user_provider
    firewall_name: secured_area
    resource_owners:
        google:
            type:                google
            client_id:           xxx.apps.googleusercontent.com
            client_secret:       xxx
            scope:               "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/drive"
    

在我获得访问令牌后,我将其设置在数据库中。然后在操作中,我创建了谷歌 API 的包装器 (new Google Client ()),并将这个客户端的访问令牌从数据库中设置。如何刷新我的访问令牌?我尝试在操作中使用谷歌 API 库的 setAccessType 和 setApprovalPrompt 函数,但没有效果。

public function __construct(array $config, LoggerInterface $symfonyLogger = null)
{
    // True if objects should be returned by the service classes.
    // False if associative arrays should be returned (default behavior).
    $config['use_objects'] = true;
    $client = new \Google_Client($config);
    if ($symfonyLogger) {
        //BC for Google API 1.0
        if (class_exists('\Google_Logger_Psr')) {
            $googleLogger = new \Google_Logger_Psr($client, $symfonyLogger);
            $client->setLogger($googleLogger);
        } else {
            $client->setLogger($symfonyLogger);
        }
    }
    $client -> setApplicationName($config['application_name']);
    $client -> setClientId($config['oauth2_client_id']);
    $client -> setClientSecret($config['oauth2_client_secret']);
    $client -> setRedirectUri($config['oauth2_redirect_uri']);
    $client -> setDeveloperKey($config['developer_key']);
    $client -> setAccessType ($config['access_type']);
    $client -> setApprovalPrompt ($config['approval_prompt']);

    $this -> client = $client;
}

配置信息如下:

    happy_r_google_api:
    application_name: carbon-quanta-137312
    oauth2_client_id: xxxx.apps.googleusercontent.com
    oauth2_client_secret: xxx
    oauth2_redirect_uri: null
    developer_key: null
    site_name: aog.local.com
    access_type: offline
    approval_prompt: force

如果在操作中我向 Google Client 设置一些参数,那么这与添加 constructorI 是相同的,那么我做错了什么?

4个回答

12

refresh_token仅在第一次请求时返回。当您第二次刷新访问令牌时,除refresh_tokenfile_put_contents之外的所有内容都会被返回,并且当这种情况发生第二次时,file_put_contents将删除refresh_token

按以下方式修改代码将原始访问令牌与新访问令牌合并(请参见:array_merge)。这样,您将能够保留未来请求所需的refresh_token。我已经向Google提交了以下修复措施,希望他们在某个时候更新它。

有关更多信息,请参见文档

    // Refresh the token if it's expired.
    if ($client->isAccessTokenExpired()) {
        $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
        $newAccessToken = $client->getAccessToken();
        $accessToken = array_merge($accessToken, $newAccessToken);
        file_put_contents($credentialsPath, json_encode($accessToken));
    }

你在哪里初始化了 $accessToken 变量? - Amir Hassan Azimi

8

一半的答案已经被Arithran回答了。

过期令牌只会在您第一次授权您的帐户时发送。之后,您将不再收到它,这就是为什么您需要从一开始就保存它,然后在每次刷新时合并旧的和新的数组。

另一半答案是如何删除并再次接收该令牌,否则您将需要每次使用新的Google账号进行测试。

  1. 前往您的帐户安全设置:https://www.google.com/settings/u/1/security
  2. 滚动到“授权应用程序和站点”部分,然后单击“查看全部”。
  3. 然后“撤销对应用程序的访问权限”。
  4. 发出新的OAuth2请求。这将返回一个refresh_token。

记得在您的请求中添加access_type=offline


如何使用客户端SDK JS发出请求? - KumailR

2
OAuth 2.0协议中,您的应用程序请求授权访问由范围标识的资源,并假定用户已通过身份验证并批准,则您的应用程序接收短期访问令牌,以便访问这些资源,以及(可选)刷新令牌以允许长期访问。
刷新令牌的想法是,如果访问令牌被攻击者窃取,因为它的有效期很短,攻击者只有有限的时间可以滥用它。
如果刷新令牌被攻击者窃取,则无用,因为攻击者需要客户端ID和密钥以及刷新令牌才能获得访问令牌。
令牌可能停止工作的原因:
- 用户已撤销访问权限。 - 该令牌未使用超过六个月。 - 用户更改了密码,而该令牌包含Gmail、日历、联系人或Hangouts范围。 - 用户帐户已超过一定数量的令牌请求。
目前每个用户账户对于每个客户端的刷新令牌数量限制为25个。如果达到了限制,创建新令牌会自动使最旧的令牌失效且不提供警告。这个限制不适用于服务帐户
以下是一个相关的 SO(Stack Overflow)讨论,解释了为什么会获得NULL令牌:获取空的刷新令牌

我更新了我的问题,在我的范围内有三个参数,并且在构造函数包装器中有access_type: offline approval_prompt: force,但仍然有过期的刷新令牌,如何更新或者可能是HWIO bundle的问题,我从HWIO获取访问令牌。因为我使用这个库还有另一个问题,我上传文件到Google Drive,但是文件为空,而且有一个create函数,但现在在重建项目和composer安装后丢失了。我认为有些地方出了问题。 - shuba.ivan

1

我明白了。我从HWIO bundle获取访问令牌,并将其添加到配置的HWIO bundle中access_type: offline,approval_prompt: force。在响应中,我有不为空的刷新令牌。

    google:
        type:                google
        client_id:           xxx
        client_secret:       xxx
        scope:               "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/drive"
        options:
            access_type:         offline
            approval_prompt:     force

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接