我正在关注以下链接中的文档:
https://developers.google.com/+/mobile/android/sign-in#enable_server-side_api_access_for_your_app
特别是说:
如果不需要脱机访问,则可以检索访问令牌并通过安全连接将其发送到服务器。您可以使用GoogleAuthUtil.getToken((直接获取访问令牌,方法是指定没有服务器OAuth 2.0客户端ID的作用域。例如:
我像这样检索访问令牌:
accessToken = GoogleAuthUtil.getToken(
AuthenticatorActivity.this,
Plus.AccountApi.getAccountName(Common.mGoogleApiClient),
"oauth2:https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/plus.login email"
);
检索访问令牌后,我将其发送到 Web 服务器,在 Web 服务器上,我可以通过调用
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='.$_POST['google_access_token']
上面的请求返回安卓应用程序客户端 ID,它还正确返回用户电子邮件。
问题是当我尝试运行$client->身份验证($_POST['google_access_token'](时;我收到消息异常:"invalid_grant:令牌类型不正确"。
为了防止获取令牌缓存,我总是使安卓应用程序中的令牌无效:
if (accessToken != null && !accessToken.isEmpty((( { GoogleAuthUtil.invalidateToken(AuthenticatorActivity.this, accessToken(; }
这是 php 代码:
if (!isset($_POST['google_access_token'])) {
throw new Exception('missing google_access_token');
}
$client = new 'Google_Client();
$client->setApplicationName("GiverHub");
$client->setClientId($this->config->item('google_client_id'));
$client->setClientSecret($this->config->item('google_client_secret'));
$client->setDeveloperKey($this->config->item('google_developer_key'));
$client->setRedirectUri($this->config->item('google_redirect_uri'));
$client->setScopes([
'https://www.googleapis.com/auth/plus.login',
'https://www.googleapis.com/auth/plus.me',
'email',
]);
try {
$client->authenticate($_POST['google_access_token']); // if i remove this the rest of the code below works! ...
$reqUrl = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='.$_POST['google_access_token'];
$req = new 'Google_Http_Request($reqUrl);
$io = $client->getIo();
$response = $io->executeRequest($req);
$response = $response[0];
$response = json_decode($response, true);
if ($response === null) {
throw new Exception('Failed to check token. response null');
}
if ($response['issued_to'] !== '466530377541-s7cfm34jpf818gbr0547pndpq9songkg.apps.googleusercontent.com') {
throw new Exception('Invalid access token. issued to wrong client id: '. print_r($response, true));
}
if (!isset($response['user_id'])) {
throw new Exception('Missing user_id');
}
if (!isset($response['email'])) {
throw new Exception('Missing email');
}
/** @var 'Entity'User $user */
$user = Common::create_member_google([
'id' => $response['user_id'],
'email' => $response['email'],
'given_name' => '',
'family_name' => '',
]);
$user->login($this->session);
if ($user instanceof 'Entity'User) {
echo json_encode( [ 'success' => true, 'user' => $user ] );
} else {
echo json_encode( [ 'success' => false, 'msg' => $user ] );
}
} catch(Exception $e) {
echo json_encode(['success' => false, 'msg' => $e->getMessage()]);
}
如果我删除 $client->authenticate((; 行,上面的代码有效...问题是我无法获得given_name/family_name等。只有来自令牌信息的电子邮件/google_user_id...
关于为什么密钥适用于令牌信息但不适用于身份验证的任何想法?
我已经尝试了许多不同的范围变体..在服务器端和安卓端..
$client->authenticate()
方法不能完全完成您要执行的操作。它从早期的 OAuth 事务中获取一次性代码,并将其交换为访问令牌。在你的例子中 - 你说你已经拥有访问令牌。
您应该能够调用$client->setAccessToken()
来设置令牌,因此它可能看起来像
$client->setAccessToken($_POST['google_access_token']);
user158443建议我使用$client->setAccessToken((之后提出的解决方案;
// first json_encode the access token before sending it to $client->setAccessToken();
$json_encoded_access_token = json_encode([
'access_token' => $_POST['google_access_token'],
'created' => time(), // make up values for these.. otherwise the client thinks the token has expired..
'expires_in' => time()+60 // made up a value in the future...
]);
// and then set it
$client->setAccessToken($json_encoded_access_token);
// and then get userinfo or whatever you want from google api !! :)
$oauth2 = new 'Google_Service_Oauth2($client);
$user_info = $oauth2->userinfo->get();
注意:如果您在生产中,"模拟"我刚刚创建的expires_in和创建可能并不明智......您可能应该先调用 tokeninfo 并从那里获取过期时间......
注意:我仍然不知道如何为此获取刷新令牌...但我的用例不需要一个。