Аутентифицировать токен доступа, предоставленный GoogleAuthUtil.getToken, после его отправки на веб-сервер php

Я следую документам по ссылке ниже:

https://developers.google.com/+/mobile/android/sign-in#enable_server-side_api_access_for_your_app

В частности, та часть, в которой говорится:

Если вам не требуется автономный доступ, вы можете получить токен доступа и отправить его на свой сервер через безопасное соединение. Вы можете получить токен доступа напрямую с помощью GoogleAuthUtil.getToken(), указав области без идентификатора клиента OAuth 2.0 вашего сервера. Например:

Я получаю токен доступа следующим образом:

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"
                );

После того, как я получаю токен доступа, я отправляю его на веб-сервер, на веб-сервере я вижу, что это действительный токен доступа, вызывая

https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='.$_POST['google_access_token']

Приведенный выше запрос возвращает идентификатор клиента приложений для Android, а также правильно возвращает электронную почту пользователей.

Проблема в том, что когда я пытаюсь запустить $client->authenticate($_POST['google_access_token']); Я получаю исключение с сообщением: «invalid_grant: неправильный тип токена».

Чтобы предотвратить кэширование getToken, я всегда аннулирую токен в приложении для Android:

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(); строка... Проблема в том, что я не могу получить заданное_имя/фамильное_имя и т.д.. только адрес электронной почты/google_user_id из tokeninfo...

Любые мысли о том, почему ключ работает для tokeninfo, но не для аутентификации?

Я пробовал много разных вариантов областей... как на стороне сервера, так и на стороне андроида...


person user158443    schedule 29.11.2014    source источник


Ответы (2)


Метод $client->authenticate() не совсем делает то, что вы пытаетесь сделать. Он берет одноразовый код из более ранней транзакции OAuth и обменивает его на токен доступа. В вашем случае вы говорите, что у вас уже есть токен доступа.

Вместо этого вы должны иметь возможность вызвать $client->setAccessToken(), чтобы установить токен, поэтому он может выглядеть примерно так:

$client->setAccessToken($_POST['google_access_token']);
person Prisoner    schedule 29.11.2014
comment
Спасибо за ваш ответ... Я попробовал то, что вы предлагаете, используя $client-›setAccessToken(); также многократно. Это не работает. $client-›setAccessToken() ожидает строку в формате json. Он также ожидает токен доступа и токен обновления. Я понятия не имею, как превратить токен доступа, сгенерированный androids getToken(), в json-строку, которая $ client-›setAccessToken() примет. - person user158443; 01.12.2014
comment
Попытка $client->setAccessToken($_POST['google_access_token']); вызывает исключение со следующим сообщением: не удалось декодировать маркер json - person user158443; 01.12.2014
comment
Я решил эту проблему, создав строку json на основе $_POST['google_access_token'] и затем вызвав $client-›setAccessToken(); - person user158443; 01.12.2014

Это решение, которое я придумал после того, как 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 и получить оттуда время истечения срока действия...

ПРИМЕЧАНИЕ. Я до сих пор не знаю, как получить токен обновления для этого... но мне он не нужен для моего случая использования..

person user158443    schedule 01.12.2014