Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/202.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Google Plus单点登录服务器流-Google#u AuthException获取OAuth2访问令牌时出错,消息:';无效的授权';_Android_Authentication_Oauth 2.0_Google Plus - Fatal编程技术网

Android Google Plus单点登录服务器流-Google#u AuthException获取OAuth2访问令牌时出错,消息:';无效的授权';

Android Google Plus单点登录服务器流-Google#u AuthException获取OAuth2访问令牌时出错,消息:';无效的授权';,android,authentication,oauth-2.0,google-plus,Android,Authentication,Oauth 2.0,Google Plus,2013年1月27日更新 我现在已经解决了这个问题,请检查接受的答案 在使用Android应用程序和PHP服务器之间的服务器端流时,我很难获取刷新令牌和访问令牌 因此,我已通过以下方法获得了我的一次性代码: AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void...

2013年1月27日更新

我现在已经解决了这个问题,请检查接受的答案


在使用Android应用程序和PHP服务器之间的服务器端流时,我很难获取刷新令牌和访问令牌

因此,我已通过以下方法获得了我的一次性代码:

AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
    @Override
    protected String doInBackground(Void... params) {

        Bundle appActivities = new Bundle();
        appActivities.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
                "http://schemas.google.com/AddActivity");
        String scopes = "oauth2:server:client_id:" + SERVER_CLIENT_ID + 
                ":api_scope:" + SCOPE_STRING;

        try {
            code = GoogleAuthUtil.getToken(
                    OneTimeCodeActivity.this,         // Context context
                    mPlusClient.getAccountName(),     // String accountName
                    scopes,                           // String scope
                    appActivities                     // Bundle bundle
            );
        } catch (IOException transientEx) {
            // network or server error, the call is expected to succeed if you try again later.
            // Don't attempt to call again immediately - the request is likely to
            // fail, you'll hit quotas or back-off.
            System.out.println(transientEx.printStactTrace());
            return "Error";
        } catch (UserRecoverableAuthException e) {
            // Recover
            code = null;
            System.out.println(e.printStackTrace());
            OneTimeCodeActivity.this.startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
        } catch (GoogleAuthException authEx) {
            // Failure. The call is not expected to ever succeed so it should not be
            // retried.
            System.out.println(authEx.printStackTrace());
            return "Error";
        } catch (Exception e) {
            System.out.println(authEx.printStackTrace());
        }
   }
上面的代码将始终弹出一条弹出消息并抛出UserRecoverableAuthException Need权限,该权限要求用户授予脱机访问权限,这意味着需要调用上面的代码两次才能检索代码并将其存储在“代码”中

我现在正试图将其发送到用PHP实现的服务器

我已经使用了快速启动,并设法使其工作

在这里,有一个signin.php示例

在这里,根据文档,这已经实现了一次性授权服务器端流程

所以现在我的问题是将这个一次性代码发送到服务器

我在这里使用了photohunt Android Auth示例

我使用了代码中的“authorization”方法,并通过如下所示的post方法调用了signin.php/connect

$app->post('/connect', function (Request $request) use ($app, $client) {
    $token = $app['session']->get('token');

    if (empty($token)) {
        // Ensure that this is no request forgery going on, and that the user
        // sending us this connect request is the user that was supposed to.
        if ($request->get('state') != ($app['session']->get('state'))) {
            return new Response('Invalid state parameter', 401);
        }

        // Normally the state would be a one-time use token, however in our
        // simple case, we want a user to be able to connect and disconnect
        // without reloading the page.  Thus, for demonstration, we don't
        // implement this best practice.
        //$app['session']->set('state', '');

        $code = $request->getContent();
        // Exchange the OAuth 2.0 authorization code for user credentials.
        $client->authenticate($code);
        $token = json_decode($client->getAccessToken());

        // You can read the Google user ID in the ID token.
        // "sub" represents the ID token subscriber which in our case
        // is the user ID. This sample does not use the user ID.
        $attributes = $client->verifyIdToken($token->id_token, CLIENT_ID)
            ->getAttributes();
        $gplus_id = $attributes["payload"]["sub"];

        // Store the token in the session for later use.
        $app['session']->set('token', json_encode($token));
        $response = 'Successfully connected with token: ' . print_r($token, true);
    }

    return new Response($response, 200);
});
现在,当我使用上述实现发送代码时,我收到500条消息,上面写着

Google_AuthException获取OAuth2访问令牌时出错,消息:“无效\u授权” 在../vendor/google/google api php client/src/auth/google_OAuth2.php第115行

在../vendor/Google/Google-api-php-client/src/Google_-client.php第131行中的Google_-OAuth2->authenticate(数组('scope'=>''),'{“令牌”:“xxxxxxxx”})

在../signin.php第99行中的Google_客户端->身份验证(“{”令牌“:“xxxxxxx”}”)

在{closure}(对象(请求))

在../vendor/symfony/http kernel/symfony/Component/HttpKernel/HttpKernel.php第117行中调用_user\u func_数组(对象(闭包)、数组(对象(请求))

在../vendor/symfony/http kernel/symfony/Component/HttpKernel/HttpKernel.php第61行中的HttpKernel->handleRaw(对象(请求),'1')

在../vendor/silex/silex/src/silex/Application.php第504行中的HttpKernel->handle(对象(请求),'1',true)

在../vendor/silex/silex/src/silex/Application.php第481行中的Application->handle(对象(请求))处

在../signin.php第139行的Application->run()处

有趣的是,我曾经工作过一次,在那里我得到了200分,但我无法重现

所以我知道我的实现肯定是错误的,但我不知道如何发送它和获取刷新令牌。我在网上找不到任何解释这一点的地方。有人能帮我吗

2014年1月16日更新

使用我可以看到从getToken生成的令牌是有效的,并且在1小时内确实有效

我可以通过改变我输入Post请求的方式来确认json格式是正确的,如果我做得不好,我将完全失败

现在,我将更深入地了解php,并查看这一节Google_OAuth2.php第115行,在该行中,Google_OAuth2.php正在破坏它,它抛出了一个Google_AuthException。代码如下,这在快速入门包中提供

/**
 * @param $service
 * @param string|null $code
 * @throws Google_AuthException
 * @return string
 */
public function authenticate($service, $code = null) {
  if (!$code && isset($_GET['code'])) {
    $code = $_GET['code'];
  }

  if ($code) {
    // We got here from the redirect from a successful authorization grant, fetch the access token
    $request = Google_Client::$io->makeRequest(new Google_HttpRequest(self::OAUTH2_TOKEN_URI, 'POST', array(), array(
      'code' => $code,
      'grant_type' => 'authorization_code',
      'redirect_uri' => $this->redirectUri,
      'client_id' => $this->clientId,
      'client_secret' => $this->clientSecret
    )));

    if ($request->getResponseHttpCode() == 200) {
      $this->setAccessToken($request->getResponseBody());
      $this->token['created'] = time();
      return $this->getAccessToken();
    } else {
      $response = $request->getResponseBody();
      $decodedResponse = json_decode($response, true);
      if ($decodedResponse != null && $decodedResponse['error']) {
        $response = $decodedResponse['error'];
      }
      throw new Google_AuthException("Error fetching OAuth2 access token, message: '$response'", $request->getResponseHttpCode());
    }
  }

  $authUrl = $this->createAuthUrl($service['scope']);
  header('Location: ' . $authUrl);
  return true;
}
我编辑了上面的代码,以确保代码、客户id和密码正确无误。这就是我现在所处的位置,我不认为这是范围问题,因为我在客户端设置中硬编码了它,但仍然不起作用。不太确定

1月23日更新


好的,我认为这是一个时间问题。我使用AuthUtil在Photohunt中使用并基于BaseActivity进行设计,在我的服务器上获得了无效的授权。如何在代码中将时间移回服务器上。我在某个地方读过我可以执行时间()-10,但不确定在哪里…

听起来您可能多次发送相同的授权码。在Android上,GoogleAuthUtil.getToken()缓存它检索到的任何令牌,包括授权代码

如果请求第二个代码而不使前一个代码无效,GoogleAuthUtil将返回相同的代码。当您尝试在服务器上交换已交换的代码时,会出现无效的\u grant错误。我的建议是在检索令牌后立即使其无效(即使您未能交换代码,也最好使用新的令牌,而不是使用旧的令牌重试)


由于其他原因,可能会返回无效的\u授权,但我猜是缓存导致了您的问题,因为您说它第一次工作。

此问题现在已解决。这是由于实现了与服务器的一次性代码交换

正如上面我的问题中所指定的,我使用photohunt示例与我的服务器进行交换。Android代码可以在下面的链接中找到

第44行是这样写的

byte[] postBody = String.format(ACCESS_TOKEN_JSON, sAccessToken).getBytes();
只有在服务器端处理JSON时,这才有效。我没有

调用$client->authenticate($code)时在php中,$code有一个JSON字符串,因此在调用时,授权代码是错误的

所以这很容易,因为我没有以正确的格式发送代码

我在挖掘和测试时发现了这一点,并创建了一个手动卷曲来测试令牌


正如Google+API中所提供的,所有示例都包含一次性代码交换,但我认为所有平台的代码都不一致,必须自己进行双重检查,以确保一切正常运行,这是我的错误。

无法使其正常工作。我认为主要问题在于com.google.android.gms.auth.UserRecoverableAuthException:NeedPermission。每当我想拿到代币的时候,我总是得到这个。一旦我提供了离线访问,我再次调用getToken并使用这个令牌,我得到了错误500。是因为我打了两次电话吗?我正在使用start
code = GoogleAuthUtil.getToken(
    OneTimeCodeActivity.this,         // Context context
    mPlusClient.getAccountName(),     // String accountName
    scopes,                           // String scope
    appActivities                     // Bundle bundle
);

GoogleAuthUtil.invalidateToken(
    OneTimeCodeActivity.this,
    code
);
byte[] postBody = String.format(ACCESS_TOKEN_JSON, sAccessToken).getBytes();