Моя первая проблема заключается в том, что когда я создаю экземпляр Google_Client и устанавливаю все необходимые scopes, configs, access types и others, а затем генерирую URL-адрес для пользователя для AUTH с помощью $client->createAuthUrl();, я разрешаю доступ к моему приложению с учетной записью 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');
Итак, следующее, что я сделал, это получить данные пользователя Google с помощью laravel-socialite. Вот данные, которые я получаю:
Код для запроса
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)
Это работает. Но когда токен нужно обновить, он не обновляется. Вместо этого я получаю
"Invalid creditianals error".
Гугл говорит, что:
"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 и отозвать доступ, предоставленный этому клиентскому приложению.
Перейдите на страницу с приложениями, имеющими доступ к вашей учетной записи:
Затем попросите их снова аутентифицировать ваше приложение. В это время вы должны увидеть маркер обновления. Убедитесь, что вы сохранили его.
вы также можете сделать
$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();
}
}
К сожалению, библиотека php так не работает. Вы должны передать ему токен обновления и попросить его получить новый. Я разместил некоторый код из одного из моих php-проектов, надеюсь, он поможет вам с larvel.
Не забудьте принять ответ, если он вам помог. Это также повысит вашу репутацию.
при подаче токена обновления я продолжаю получать сообщение «отсутствует ключ json в поле client_id в .../vendor/google/auth/src/Credentials/UserRefreshCredentials.php:70», на удивление, последние пару месяцев все работало нормально. Как вы в итоге решили это?
Позвольте мне поделиться тем, что я наконец придумал в 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();
}
}
По моему опыту:
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,
]);
Я использовал автономный доступ, и по первому запросу, когда пользователь разрешает приложению использовать свою учетную запись, я получил токен обновления. Я использую этот токен обновления, чтобы получить токен доступа в автономном запросе. Таким образом, мне не нужно отслеживать, истек ли срок действия токена или что-то в этом роде. Я могу дать образец кода, если он вам нужен.
@KristianVasilev спасибо, что поделились. Я считаю, что это зависит от приложения. Мое приложение также использовало Google API в автономном режиме. Вот почему мне нужны были жетоны в первую очередь. Приложение всегда было включено, отправляя около 4 запросов в секунду. Каждый запрос токена является попаданием в Google API. Это влияет на ограничения использования API. Запрос маркеров обновления и доступа считается за 2 обращения. Итак, помимо использования как такового, моей целью было минимизировать количество запросов к API. Однако, если это не относится к вашему приложению, я согласен, чем проще, тем лучше. В любом случае нет необходимости запрашивать токен обновления, он не меняется для каждого пользователя.
Большое спасибо! Я получил токен обновления. Итак, теперь я буду хранить этот токен обновления, и каждый раз, когда он истечет, клиент будет получать новый токен, верно? Мне не нужно записывать время, которое истечет, чтобы взять новый токен и тому подобное?