在将GoogleAuthUtil.getToken发送到php Web服务器后对其进行身份验证


Authenticate access token provided by GoogleAuthUtil.getToken after sending it to php web server

我正在关注以下链接中的文档:

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 并从那里获取过期时间......

注意:我仍然不知道如何为此获取刷新令牌...但我的用例不需要一个。