#laravel #laravel-5 #google-api #google-api-php-client #google-oauth
#laravel #laravel-5 #google-api #google-api-php-client #google-oauth
Вопрос:
Моя первая проблема заключается в том, что когда я создаю экземпляр Google_Client
и устанавливаю все необходимые scopes
, configs
, access types
и others
, а затем генерирую URL-адрес для авторизации пользователя с $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 работает в автономном режиме
После того, как пользователь предоставит автономный доступ к запрошенным областям, вы можете продолжать использовать клиент API для доступа к API Google от имени пользователя, когда пользователь находится в автономном режиме. Клиентский объект обновит токен доступа по мере необходимости.
Итак, я устанавливаю токен, который я получаю из запроса и сохраняю в базе данных, в Google_Client
экземпляр с
$client->setAccessToken(Auth::user()->getUserInfo()->refresh_token)
Это работает. Но когда токен нуждается в обновлении, он не обновляется. Вместо этого я получаю
«Ошибка недопустимого creditianals».
Google говорит, что:
«Клиентский объект обновит токен доступа по мере необходимости». Но этого не происходит.
Я не понимаю, нужно ли мне вызывать специальный метод или как Google_Client
обрабатывает обновление токена.
Я попытался использовать CODE parameter
для извлечения токена и обновления токена с его помощью.
$client->fetchAccessTokenWithAuthCode($code);
И получил эту ошибку:
array:2 [▼
"error" => "invalid_request"
"error_description" => "Could not determine client ID from request."
]
Я, вероятно, что-то делаю не так, но я понятия не имею, что.
Честно говоря, я в замешательстве. Уже потерял день на этом без какого-либо успеха.
Ответ №1:
Вы получите токен обновления обратно только при первом запросе доступа пользователя. После этого Google предполагает, что вы сохранили токен обновления.
Попросите пользователя зайти в свою учетную запись Google и отозвать доступ, предоставленный этому клиентскому приложению.
Перейдите на страницу, на которой показаны приложения с доступом к вашей учетной записи:
- https://myaccount.google.com/u/0/permissions.
- В меню сторонних приложений выберите свое приложение.
- Нажмите Удалить доступ, а затем нажмите Ok для подтверждения
Затем попросите их снова аутентифицировать ваше приложение. В это время вы должны увидеть ток обновления. Убедитесь, что вы сохранили его.
отменить
вы также можете сделать
$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']) amp;amp; $_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']) amp;amp; $_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();
}
}
Комментарии:
1. Большое вам спасибо! Я получил токен обновления. Итак, теперь я буду хранить этот токен обновления, и каждый раз, когда он истекает, клиент будет получать новый токен по нему, верно? Мне не нужно беспокоиться о регистрации времени, которое истечет, чтобы принять новый токен и тому подобное?
2. К сожалению, библиотека php работает не так. Вы должны передать ему токен обновления и сообщить ему, чтобы он извлек новый. Я опубликовал некоторый код из одного из моих php-проектов, надеюсь, он поможет вам с larvel.
3. Не забудьте принять ответ, если это помогло вам. Это также повысит вашу репутацию.
4. при подаче токена обновления я продолжаю получать «ключ json отсутствует в поле client_id в … / vendor / google /auth / src /Credentials /UserRefreshCredentials.php: 70» удивительно, но последние пару месяцев все работало нормально. Как вы в конечном итоге решили это?
Ответ №2:
Позвольте мне поделиться тем, что я наконец придумал в 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() всегда возвращает значение true, если только «создано» не указано в $google_client_token, поскольку «создано» учитывается при истечении срока действия
- 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,
]);
Комментарии:
1. Я использовал автономный доступ, и по первому запросу, когда пользователь разрешает приложению использовать свою учетную запись, я получил токен обновления. Я использую этот токен обновления, чтобы получить с ним токен доступа в автономном запросе. Таким образом, мне не нужно отслеживать, истек ли срок действия токена или что-то в этом роде. Я могу привести пример кода, если он вам нужен.
2. @KristianVasilev спасибо, что поделились. Я считаю, что это зависит от приложения. Мое приложение также использовало Google API в автономном режиме. Вот почему мне нужны были токены в первую очередь. Приложение всегда было «включено», отправляя около 4 запросов в секунду. Каждый запрос токена попадает в Google API. Это влияет на ограничения использования API. Запрос как на обновление, так и на токены доступа считается за 2 попадания. Итак, помимо использования как такового, моей целью было минимизировать количество запросов API. Однако, если это не относится к вашему приложению, я согласен, чем проще, тем лучше. В любом случае нет необходимости запрашивать токен обновления, он не меняется для каждого пользователя