未经授权的谷歌访问令牌

Posted

技术标签:

【中文标题】未经授权的谷歌访问令牌【英文标题】:Google Access Token without authorization 【发布时间】:2020-03-24 13:05:35 【问题描述】:

我正在开发用于从谷歌分析帐户获取额外数据的模块。要获取此数据,Google 需要 access_token。 这就是我到目前为止所管理的

if (isset($_GET['code'])) 
    // try to get an access token
    $code = $_GET['code'];
    $url = 'https://accounts.google.com/o/oauth2/token';
    $params = array(
        "code" => $code,
        "client_id" => "559825975819-881lg83vs8feo70v5unqa8kfoijuvfnn.apps.googleusercontent.com",
        "client_secret" => "vj4UNNItAJocX4RkNaD_3DQ4",
        "redirect_uri" => 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["php_SELF"],
        "access_type" => "offline",
        "grant_type" => "authorization_code"
    );

    $ch = curl_init();
    curl_setopt($ch, constant("CURLOPT_" . 'URL'), $url);
    curl_setopt($ch, constant("CURLOPT_" . 'POST'), true);
    curl_setopt($ch, constant("CURLOPT_" . 'POSTFIELDS'), $params);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $output = curl_exec($ch);
    $info = curl_getinfo($ch);
    curl_close($ch);
 $data = (json_decode($output, true));


 $access_token_var = $data['access_token'];

  echo $access_token_var;

 else 

    $url = "https://accounts.google.com/o/oauth2/auth";

    $params = array(
        "response_type" => "code",
        "client_id" => "559825975819-881lg83vs8feo70v5unqa8kfoijuvfnn.apps.googleusercontent.com",
        "redirect_uri" => 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PHP_SELF"],
        "scope" => "https://www.googleapis.com/auth/analytics",
        "access_type" => "offline",
        "approval_prompt" => "force"
    );

    $request_to = $url . '?' . http_build_query($params);

    header("Location: " . $request_to);

我得到了 access_token,它在需要的变量中回显。但是我想在后台获取分析附加数据(例如,当客户下订单并点击订单按钮时​​),但每次我需要新的access_token时,我都需要用我的google帐户授权,因此,网站上的每个客户都需要为此,尽管我设置了“access_type”=>“offline”。怎么了?还是我的 API 应用有问题?

【问题讨论】:

可能是 Google 仅在用户第一次授予应用程序访问他的帐户时才返回刷新令牌。您可以尝试撤销批准(在您的 Google 帐户中),然后再次批准申请。 可能重复:***.com/questions/10827920/… 【参考方案1】:

访问令牌会在短时间内过期。每次过期都需要刷新访问令牌。

https://developers.google.com/identity/protocols/OAuth2WebServer

访问令牌会定期过期。如果您请求对与令牌关联的范围进行离线访问,则可以在不提示用户许可的情况下刷新访问令牌(包括当用户不存在时)。

您无需刷新即可自行访问令牌。您可以使用 Goggle php 库 https://github.com/googleapis/google-api-php-client 以便它可以自动刷新令牌。这是一个来自谷歌网站的例子。

$client = new Google_Client();
$client->setAuthConfig('client_secrets.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) 
  $client->setAccessToken($_SESSION['access_token']);
  $drive = new Google_Service_Drive($client);
  $files = $drive->files->listFiles(array())->getItems();
  echo json_encode($files);
 else 
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));

如果您不想或不能使用 Google Php 库,当您将授权代码换成访问令牌时,Google 的授权服务器会返回一个刷新令牌。然后,如果访问令牌过期(或在任何其他时间),您可以使用刷新令牌来获取新的访问令牌。您可以使用通过 curl 获取访问令牌的相同方式,但使用不同的参数。

POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

client_id=<your_client_id>&
client_secret=<your_client_secret>&
refresh_token=<refresh_token>&
grant_type=refresh_token

【讨论】:

【参考方案2】:

Refreshing an access token (offline access)

访问令牌会定期过期。如果您请求对与令牌关联的范围进行离线访问,则可以在不提示用户许可的情况下刷新访问令牌(包括当用户不存在时)。

如果您使用 Google API Client Library,只要您将该对象配置为离线访问,客户端对象就会根据需要刷新访问令牌。

如果不使用客户端库,则需要在redirecting the user to Google's OAuth 2.0 server时将access_type HTTP查询参数设置为offline。在这种情况下,当您 exchange an authorization code 获取访问令牌时,Google 的授权服务器会返回一个刷新令牌。然后,如果访问令牌过期(或在任何其他时间),您可以使用刷新令牌来获取新的访问令牌。

请求离线访问是任何需要在用户不在场时访问 Google API 的应用程序的要求。例如,在预定时间执行备份服务或执行操作的应用程序需要能够在用户不在时刷新其访问令牌。默认的访问方式称为在线。

服务器端 Web 应用程序、已安装的应用程序和设备都在授权过程中获取刷新令牌。刷新令牌通常不用于客户端 (javascript) Web 应用程序。

请求刷新令牌

对于那些使用 PHP 的 Google API 客户端库并寻求离线访问和刷新令牌的用户,请注意在撰写本文时文档显示的示例不正确。

目前正在显示:

$client = new Google_Client();
$client->setAuthConfig('client_secret.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');

// offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.

$client->setAccessType('offline');

// Using "consent" ensures that your application always receives a refresh token.
// If you are not using offline access, you can omit this.

$client->setApprovalPrompt("consent");
$client->setIncludeGrantedScopes(true);   // incremental auth

来源:https://developers.google.com/identity/protocols/OAuth2WebServer#offline

所有这些都很好——除了一件

$client->setApprovalPrompt("consent");

经过一番推理,我将此行更改为以下内容,一切正常

$client->setPrompt("consent");

这是有道理的,因为使用 HTTP 请求时,它已从 #approval_prompt=force# 更改为 #prompt=consent#。因此,将 setter 方法从 setApprovalPrompt 更改为 setPrompt 遵循自然约定 - 但它不在文档中!我至少找到了。

【讨论】:

以上是关于未经授权的谷歌访问令牌的主要内容,如果未能解决你的问题,请参考以下文章

获取我的谷歌服务帐户的授权令牌密钥

访问谷歌文档的用户的谷歌账户授权

如何从PHP脚本访问我的谷歌驱动器,无需手动授权

没有浏览器的谷歌驱动器登录api

laravel socialite 从谷歌授权码获取谷歌访问令牌

刷新谷歌访问令牌时未授权_客户端