duanbarong4617 2014-11-29 08:24
浏览 192
已采纳

将GoogleAuthUtil.getToken提供的访问令牌发送到php Web服务器后进行身份验证

I am following the docs from link below:

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

Specifically the part that says:

If you do not require offline access, you can retrieve the access token and send it to your server over a secure connection. You can obtain the access token directly using GoogleAuthUtil.getToken() by specifying the scopes without your server's OAuth 2.0 client ID. For example:

I retrieve the access token like this:

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

After I retrieve the access token I send it to a web server, on the web server i can see that it's a valid access token by calling

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

The request above returns the android apps client id, it also returns the users email correctly.

The problem is that when I try to run $client->authenticate($_POST['google_access_token']); I get an exception with the message: "invalid_grant: Incorrect token type".

To prevent getToken caching I always invalidate the token in android app:

if (accessToken != null && !accessToken.isEmpty()) { GoogleAuthUtil.invalidateToken(AuthenticatorActivity.this, accessToken); }

Here's the php code:

        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()]);
    }

The above code works if i remove the $client->authenticate(); line ... The problem is that I can't get the given_name / family_name etc .. only email / google_user_id from the tokeninfo ...

Any thoughts about why the key works for tokeninfo but not for authenticate?

I have tried many different variations of the scopes .. both on the server side and the android side ..

  • 写回答

2条回答 默认 最新

  • doudong7256 2014-12-01 15:56
    关注

    This is the solution I came up with after user158443 suggested I use $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();
    

    NOTE: it's probably not smart to "emulate" the expires_in and created that i just did if you are in production ... You should probably call tokeninfo first and get the expires time from there...

    NOTE: I still have no idea how to get a refresh token for this... but I don't need one for my use case..

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥66 定制开发肯德基自动化网站下单软件
  • ¥20 vscode虚拟环境依赖包未安装
  • ¥15 odoo17关于owl开发js代码问题
  • ¥15 光纤中多普勒频移公式的推导
  • ¥15 怎么制作一个人脸识别门禁系统
  • ¥20 大华dss监控平台网络关闭登不进去
  • ¥15 请使用蚁群算法解决下列问题,并给出我完整的代码
  • ¥20 关于php录入完成后,批量更新数据库
  • ¥15 请教往复密封润滑问题
  • ¥15 cocos creator发布ios包