【问题标题】:Why curls fails to verify google access token whereas browser succeeds?为什么 curls 无法验证谷歌访问令牌而浏览器成功?
【发布时间】:2018-06-05 01:28:51
【问题描述】:

通过这个简单的代码,我设法获得了 Google 的访问令牌。 见代码:

public function authenticate($code = null) {
  if (!$code) {
     if ($this->log)
        error_log(__CLASS__ . '::authenticate() error: $code is null.');
     return false;
  }
  $client_id = $this->token->get('client_id');
  $client_secret  = $this->token->get('client_secret');
  $redirect_uri = $this->token->get('redirect_uri');
  $url = $this->token->get('token_endpoint');
  $curlPost = 'client_id=' . $client_id . '&client_secret=' . $client_secret . '&redirect_uri=' . $redirect_uri . '&code='. $code . '&grant_type=authorization_code';
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
  $buffer = curl_exec($ch);
  $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  curl_close($ch);
  $data = \json_decode($buffer, true);
  if ($http_code != 200) {
     $log = __CLASS__ . '::authenticate() error: http code not 200. Responded: '.print_r($data, true);
     $return = false;
  } else {
     $this->auth = $data;
     $return = true;
     $log = __CLASS__ . '::authenticate() returns '.$return.' and sets this->auth='.print_r($data, true);
  }
  if ($this->log)
     error_log($log);
  return $return;
}

你可以看到我的项目there 有一个测试文件。

我的问题是关于verify() 函数。 当我想通过在浏览器中输入 https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=.... 之类的内容来验证 Google 的访问令牌时,我会立即收到来自 Google 的响应,但是当我尝试使用 cURL 执行以下功能时,它会惨遭失败:

public function verify($access_token = null) {
  if (!$access_token) {
     if ($this->log)
        error_log(__CLASS__ . '::verify() error: $access_token is null.');
     return false;
  }
  $url = $this->token->get('verify_endpoint');
  $curlPost = 'access_token='. $access_token;
  //$curlPost = \http_build_query(array('access_token' => $access_token));
  //$curlPost = array('access_token' => $access_token);
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url.'?'.$curlPost);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
  //curl_setopt($ch, CURLOPT_VERBOSE, true);
  $buffer = curl_exec($ch);
  $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  curl_close($ch);
  $data = \json_decode($buffer, true);
  if ($http_code != 200) {
     $log = __CLASS__ . '::verify() error: http code not 200. Responded: '.print_r($data, true);
     $return = false;
  } else {
     $this->verify = $data;
     $log = __CLASS__ . '::verify() sets this->verify='.print_r($data, true);
     $return = true;
  }
  if ($this->log)
     error_log($log);
  return $return;
}

这和cURL有关系吗?欢迎任何答案。

澄清一下:浏览器请求https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=...?id_token=... 总是成功但不是cURL,当然在查询部分使用proper 标记。

【问题讨论】:

  • 我无法回答。但是在第一个代码块中:$curlPost = 'client_id=' . $client_id . '&client_secret=' ...... 很糟糕,因为您没有对 URI 字符串进行编码。只需让$curlPost 一个关联数组传递它curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost); 让 curl 完成 URI 编码工作
  • $url = $this->token->get('verify_endpoint');
  • @DaImTo 是的,代码使用了一些辅助类,如 github 项目 (github.com/centurianii/googleclient);这是存储在 GoogleToken 类中的实际验证 url
  • @Paolo 我可以进行身份​​验证,我可以使用我的浏览器进行验证,但 curl 仍然无法通过消息进行验证:Array ([error_description] => Unsupported content with type: multipart/form-data;boundary=- -----------------------4771c015d2208399)
  • 我怀疑我在 verify() 中使用 curl 的方式不是一个明确的 GET 请求;最后我根本不应该验证,但我仍然想知道为什么 curl 失败了?

标签: google-oauth php-curl


【解决方案1】:

问题解决了!

经过 2 个月的搜索终于有一个更新版本我的项目 wirh cUrl 问题在开始调查 curl 环境发送的错误后立即解决。

浏览器的成功敲响了警钟,可能存在DNS 问题,因为这些线程反复展示了这一点:

  1. https://curl.haxx.se/mail/curlphp-2016-10/0000.html
  2. https://forums.rancher.com/t/dns-caching-issues/1566/8@vincent
  3. https://github.com/GoogleCloudPlatform/google-cloud-php/issues/405
  4. https://github.com/google/google-api-php-client/issues/1184

来自@sanmai 的关于CURLOPT_RESOLVEThis 讨论实际上使它起作用了!另见php manual; Luc van Donkersgoed 提出了 here 和 John Hart 提出的 there 也是如此。

hereother 的地方讨论了包含 Google 响应的 GET 请求的响应标头的棘手部分。

Curl 证书从there 下载。 证书的讨论是there

关于调试cUrlherethere的讨论。

有关Expect 标头及其含义的讨论,您可以阅读thisthat

现在cUrl 连接到谷歌时速度快如闪电。见我的project

我向所有耐心和善意地支持社区的用户表示最深切的感谢。你们真棒!非常感谢!

【讨论】:

    【解决方案2】:

    来自您的源代码here

    $this->set('verify_endpoint', 'https://www.googleapis.com/oauth2/v2/tokeninfo');

    正在调用谷歌令牌信息端点documentation 用于验证您似乎正在向其传递访问令牌的 id 令牌。这是行不通的。

    TBH 我不明白您为什么要费心验证访问令牌。测试访问令牌是否有效的最佳方法是调用有问题的 API,如果它不起作用,您将收到错误消息。你为什么要打电话来测试它是否有效,然后使用它,如果它确实有效,你的请求加倍。

    【讨论】:

    • 好的,我有访问令牌,我在浏览器中输入了:https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=ya29.Gl...,我可以立即看到响应!我的问题是 curl 等价物是怎么回事。你建议不要做这一步?
    • 我从浏览器传递id_token:成功,从curl:失败!我怀疑 curl 在这里没有发出明确的 GET 请求...
    • 可能是因为你给 curl 的不是 id 令牌,而是访问令牌。通过 http get 传递 Id_token 将起作用。你为什么要费心测试这个?
    • $curlPost = 'token_id='。 $token_id;
    • 我记录了谷歌的回复,所以我可以看到Array ( [access_token] => ya29.G...O0 [expires_in] => 3600 [id_token] => eyJhb...Obg [refresh_token] => 1/wLy...9i [token_type] => Bearer )
    猜你喜欢
    • 2016-07-29
    • 2021-01-04
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多