google-api 如何在带令牌的离线请求中工作
How does google-api work in offline request with tokens
我的第一个问题是,当我创建 Google_Client
实例并设置所有需要的 scopes
、configs
、access types
和 others
以及然后为用户生成一个 URL 以使用 $client->createAuthUrl();
进行 AUTH 我允许使用我登录的 google 帐户访问我的应用程序。一切正常,直到我需要刷新令牌。
我在下面解释令牌刷新。
$this->client = new Google_Client();
$this->client->setAuthConfig(Storage::path('secret.json'));
$this->client->setAccessType("offline"); // offline access
$this->client->setIncludeGrantedScopes(true); // incremental auth
$this->client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$this->client->setRedirectUri(env('APP_URL') . '/login/google/callback');
所以我接下来要做的是使用 laravel-socialite.
获取 google 用户数据 这是我获取的数据:
请求代码
public function redirectToGoogleProvider()
{
$parameters = ['access_type' => 'offline'];
return Socialite::driver('google')
->scopes(["https://www.googleapis.com/auth/drive"])
->with($parameters)
->redirect();
}
User {#466 ▼
+token: "ya29.GmPhBiSuYJ_oKsvDTUXrj3lJR5jlEYV4x8d0ZuYZLnDJgYL-uePT_KuUkIb-OQUiWBElhm6ljfac5QhDTXYK3qjWjje1vsnZsTAJ7pXyjNAVd2buZy0a6xZCTdnLdFNMKMDMXa6bGbA"
+refreshToken: null
+expiresIn: 3599
+id: "101509757451285102354"
+nickname: null
+name: "My name"
+email: "My email"
+avatar: "https://lh3.googleusercontent.com/-Qsbr3VmcZ50/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3rdS2HIl3LCv5EYCmvyXulG8n-Ap7w/mo/photo.jpg"
+user: array:12 [▶]
+"avatar_original": "https://lh3.googleusercontent.com/-Qsbr3VmcZ50/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3rdS2HIl3LCv5EYCmvyXulG8n-Ap7w/mo/photo.jpg"
}
这里没有刷新令牌。我认为这是因为 google 在 离线模式
下的工作方式
After a user grants offline access to the requested scopes, you can
continue to use the API client to access Google APIs on the user's
behalf when the user is offline. The client object will refresh the
access token as needed.
所以我将从请求中获取的令牌设置为
并存储在数据库中的 Google_Client
实例
$client->setAccessToken(Auth::user()->getUserInfo()->refresh_token)
这行得通。但是当token需要刷新的时候却没有刷新。相反,我得到
"Invalid creditianals error".
Google 表示:
"The client object will refresh the access token as needed." But this
is not happening.
我不明白如果我需要调用一个特殊的方法或者 Google_Client
如何处理令牌刷新。
我试过使用 CODE parameter
获取令牌并用它刷新令牌。
$client->fetchAccessTokenWithAuthCode($code);
并得到这个错误:
array:2 [▼
"error" => "invalid_request"
"error_description" => "Could not determine client ID from request."
]
我可能做错了什么,但我不知道是什么。
老实说,我很困惑。已经为此浪费了一天时间,但没有任何成功。
您只会在第一次请求用户访问时获得一个刷新令牌。之后 Google 假设您保存了刷新令牌。
让用户转到他们的 google 帐户并撤销授予此客户端应用程序的访问权限。
转到显示有权访问您帐户的应用程序的页面:
- https://myaccount.google.com/u/0/permissions.
- 在“第三方应用”菜单下,选择您的应用。
- 单击“删除访问权限”,然后单击“确定”进行确认
然后让他们再次验证您的应用程序。那时您应该会看到刷新标记。确保保存它。
撤销
您也许还可以做到
$client->revokeToken();
这应该撤销用户授予的访问权限。但是我还没有尝试过看看它是否能给我一个新的刷新令牌。
刷新访问权限
这是我用于刷新访问令牌的代码 注意它 PHP 我不是一个 larvel 开发者它看起来非常接近如果它不能开箱即用你应该能够隐藏它
/**
* Authenticating to Google using Oauth2
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Returns a Google client with refresh token and access tokens set.
* If not authencated then we will redirect to request authencation.
* @return A google client object.
*/
function getOauth2Client() {
try {
$client = buildClient();
// Set the refresh token on the client.
if (isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
}
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
$_SESSION['access_token'] = $client->getAccessToken();
}
return $client;
} else {
// We do not have access request access.
header('Location: ' . filter_var( $client->getRedirectUri(), FILTER_SANITIZE_URL));
}
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
让我分享一下我终于在 Laravel 想出的东西
public static function getOauth2Client($o_user, $f_client) {
try {
$o_client = new Google_Client();
$o_client - >setAuthConfig($f_client);
$o_client - >setAccessType('offline');
$o_client - >setIncludeGrantedScopes(true);
$i_token_remaining = ($o_user - >gdrive_access_ttl - (time() - $o_user - >gdrive_access_created));
$google_client_token = ['refresh_token' = >$o_user - >gdrive_refresh_token, 'access_token' = >$o_user - >gdrive_access_token, 'created' = >$o_user - >gdrive_access_created, 'expires_in' = >$i_token_remaining, ];
$o_client - >setAccessToken(json_encode($google_client_token));
#token validity time is less than 60 seconds
if ($i_token_remaining < 60 || $o_client - >isAccessTokenExpired()) {
$res = $o_client - >fetchAccessTokenWithRefreshToken($o_client - >getRefreshToken());
$o_user - >gdrive_access_token = $res['access_token'];
$o_user - >gdrive_access_created = time();
$o_user - >gdrive_access_ttl = $res['expires_in'];
}
return $o_client;
} catch(Exception $e) {
print 'An error occurred: '.$e - >getMessage();
}
}
根据我的经验:
- setAccessToken 不适用于仅提供的令牌,它需要我 "expires_in"
- $o_client->isAccessTokenExpired() 总是 returns true 除非 "created" 与 $google_client_token 一起提供,因为 "created" 被考虑过期
- isAccessTokenExpired 在到期前 30 秒进行检查,因此可以安全地删除我的 60 秒检查
- $o_user 是用户对象,例如User::find($i_user_id);
- 刷新令牌永远不会改变,它被设置一次,永远,它只是访问令牌,每当请求刷新时都会改变
- 访问令牌 ttl 是 3600 - 猜猜为什么?)) - 所以请存储和更新访问令牌
- 超出此功能的范围,一旦访问令牌更改,我也会更新我的数据库
User::updateOrCreate(
['email' => $o_user - > email],
[
'gdrive_access_token' => $o_user - > gdrive_access_token,
'gdrive_access_created' => $o_user - > gdrive_access_created,
'gdrive_access_ttl' => $o_user - > gdrive_access_ttl,
]);
我的第一个问题是,当我创建 Google_Client
实例并设置所有需要的 scopes
、configs
、access types
和 others
以及然后为用户生成一个 URL 以使用 $client->createAuthUrl();
进行 AUTH 我允许使用我登录的 google 帐户访问我的应用程序。一切正常,直到我需要刷新令牌。
我在下面解释令牌刷新。
$this->client = new Google_Client();
$this->client->setAuthConfig(Storage::path('secret.json'));
$this->client->setAccessType("offline"); // offline access
$this->client->setIncludeGrantedScopes(true); // incremental auth
$this->client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$this->client->setRedirectUri(env('APP_URL') . '/login/google/callback');
所以我接下来要做的是使用 laravel-socialite.
获取 google 用户数据 这是我获取的数据:
请求代码
public function redirectToGoogleProvider()
{
$parameters = ['access_type' => 'offline'];
return Socialite::driver('google')
->scopes(["https://www.googleapis.com/auth/drive"])
->with($parameters)
->redirect();
}
User {#466 ▼
+token: "ya29.GmPhBiSuYJ_oKsvDTUXrj3lJR5jlEYV4x8d0ZuYZLnDJgYL-uePT_KuUkIb-OQUiWBElhm6ljfac5QhDTXYK3qjWjje1vsnZsTAJ7pXyjNAVd2buZy0a6xZCTdnLdFNMKMDMXa6bGbA"
+refreshToken: null
+expiresIn: 3599
+id: "101509757451285102354"
+nickname: null
+name: "My name"
+email: "My email"
+avatar: "https://lh3.googleusercontent.com/-Qsbr3VmcZ50/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3rdS2HIl3LCv5EYCmvyXulG8n-Ap7w/mo/photo.jpg"
+user: array:12 [▶]
+"avatar_original": "https://lh3.googleusercontent.com/-Qsbr3VmcZ50/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3rdS2HIl3LCv5EYCmvyXulG8n-Ap7w/mo/photo.jpg"
}
这里没有刷新令牌。我认为这是因为 google 在 离线模式
下的工作方式After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.
所以我将从请求中获取的令牌设置为
并存储在数据库中的Google_Client
实例
$client->setAccessToken(Auth::user()->getUserInfo()->refresh_token)
这行得通。但是当token需要刷新的时候却没有刷新。相反,我得到
"Invalid creditianals error".
Google 表示:
"The client object will refresh the access token as needed." But this is not happening.
我不明白如果我需要调用一个特殊的方法或者 Google_Client
如何处理令牌刷新。
我试过使用 CODE parameter
获取令牌并用它刷新令牌。
$client->fetchAccessTokenWithAuthCode($code);
并得到这个错误:
array:2 [▼
"error" => "invalid_request"
"error_description" => "Could not determine client ID from request."
]
我可能做错了什么,但我不知道是什么。 老实说,我很困惑。已经为此浪费了一天时间,但没有任何成功。
您只会在第一次请求用户访问时获得一个刷新令牌。之后 Google 假设您保存了刷新令牌。
让用户转到他们的 google 帐户并撤销授予此客户端应用程序的访问权限。
转到显示有权访问您帐户的应用程序的页面:
- https://myaccount.google.com/u/0/permissions.
- 在“第三方应用”菜单下,选择您的应用。
- 单击“删除访问权限”,然后单击“确定”进行确认
然后让他们再次验证您的应用程序。那时您应该会看到刷新标记。确保保存它。
撤销
您也许还可以做到
$client->revokeToken();
这应该撤销用户授予的访问权限。但是我还没有尝试过看看它是否能给我一个新的刷新令牌。
刷新访问权限
这是我用于刷新访问令牌的代码 注意它 PHP 我不是一个 larvel 开发者它看起来非常接近如果它不能开箱即用你应该能够隐藏它
/**
* Authenticating to Google using Oauth2
* Documentation: https://developers.google.com/identity/protocols/OAuth2
* Returns a Google client with refresh token and access tokens set.
* If not authencated then we will redirect to request authencation.
* @return A google client object.
*/
function getOauth2Client() {
try {
$client = buildClient();
// Set the refresh token on the client.
if (isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
}
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
$_SESSION['access_token'] = $client->getAccessToken();
}
return $client;
} else {
// We do not have access request access.
header('Location: ' . filter_var( $client->getRedirectUri(), FILTER_SANITIZE_URL));
}
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
让我分享一下我终于在 Laravel 想出的东西
public static function getOauth2Client($o_user, $f_client) {
try {
$o_client = new Google_Client();
$o_client - >setAuthConfig($f_client);
$o_client - >setAccessType('offline');
$o_client - >setIncludeGrantedScopes(true);
$i_token_remaining = ($o_user - >gdrive_access_ttl - (time() - $o_user - >gdrive_access_created));
$google_client_token = ['refresh_token' = >$o_user - >gdrive_refresh_token, 'access_token' = >$o_user - >gdrive_access_token, 'created' = >$o_user - >gdrive_access_created, 'expires_in' = >$i_token_remaining, ];
$o_client - >setAccessToken(json_encode($google_client_token));
#token validity time is less than 60 seconds
if ($i_token_remaining < 60 || $o_client - >isAccessTokenExpired()) {
$res = $o_client - >fetchAccessTokenWithRefreshToken($o_client - >getRefreshToken());
$o_user - >gdrive_access_token = $res['access_token'];
$o_user - >gdrive_access_created = time();
$o_user - >gdrive_access_ttl = $res['expires_in'];
}
return $o_client;
} catch(Exception $e) {
print 'An error occurred: '.$e - >getMessage();
}
}
根据我的经验:
- setAccessToken 不适用于仅提供的令牌,它需要我 "expires_in"
- $o_client->isAccessTokenExpired() 总是 returns true 除非 "created" 与 $google_client_token 一起提供,因为 "created" 被考虑过期
- isAccessTokenExpired 在到期前 30 秒进行检查,因此可以安全地删除我的 60 秒检查
- $o_user 是用户对象,例如User::find($i_user_id);
- 刷新令牌永远不会改变,它被设置一次,永远,它只是访问令牌,每当请求刷新时都会改变
- 访问令牌 ttl 是 3600 - 猜猜为什么?)) - 所以请存储和更新访问令牌
- 超出此功能的范围,一旦访问令牌更改,我也会更新我的数据库
User::updateOrCreate(
['email' => $o_user - > email],
[
'gdrive_access_token' => $o_user - > gdrive_access_token,
'gdrive_access_created' => $o_user - > gdrive_access_created,
'gdrive_access_ttl' => $o_user - > gdrive_access_ttl,
]);