Android Google Plus单点登录服务器流-Google#u AuthException获取OAuth2访问令牌时出错,消息:';无效的授权';
2013年1月27日更新 我现在已经解决了这个问题,请检查接受的答案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...
在使用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();