我正在尝试将“使用 Google 登录”集成到具有以下功能的应用程序中:android
和网络组件。通过以下步骤,Web 组件中的所有内容都可以正常工作:
1. 使用防伪令牌、客户端 ID 和应用程序名称渲染视图。
$state = md5(rand());
Session::set('state', $state);
$this->view->render('login', array(
'CLIENT_ID' => 'my_web_client_id',
'STATE' => $state,
'APPLICATION_NAME' => 'my_app_name'));
2. 当用户点击Google的登录按钮时,从Google的服务器获取一次性代码并将其发送到我的服务器。
3. 在我的服务器收到一次性代码后,使用https://github.com/google/google-api-php-client https://github.com/google/google-api-php-client使用该代码对用户进行身份验证。
if ($_SESSION['state'] != $_POST['state']) { // Where state is the anti-forgery token
return 'some error';
}
$code = $_POST['code'];
$client = new Google_Client();
$client->setApplicationName("my_app_name");
$client->setClientId('my_web_client_id');
$client->setClientSecret('client_secret');
$client->setRedirectUri('postmessage');
$client->addScope("https://www.googleapis.com/auth/urlshortener");
$client->authenticate($code);
$token = json_decode($client->getAccessToken());
// Verify the token
$reqUrl = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' . $token->access_token;
$req = new Google_Http_Request($reqUrl);
$tokenInfo = json_decode($client->getAuth()->authenticatedRequest($req)->getResponseBody());
// If there was an error in the token info, abort.
if ($tokenInfo->error) {
return 'some error';
}
// Make sure the token we got is for our app.
if ($tokenInfo->audience != "my_web_client_id") {
return 'some error';
}
// Saving user in db
...
// Load the app view
现在,Android 客户端应该类似吧?按照这些教程进行操作:https://developers.google.com/+/mobile/android/sign-in https://developers.google.com/+/mobile/android/sign-in and http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/ http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/
执行异步任务onConnected
method
class CreateToken extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... voids) {
oneTimeCode = getOneTimeCode();
String email = getUserGPlusEmail();
try {
// Opens connection and sends the one-time code and email to the server with 'POST' request
googleLogin(oneTimeCode, email);
} catch (IOException e) {
e.printStackTrace();
}
return oneTimeCode;
}
}
private String getOneTimeCode() {
String scopes = "oauth2:server:client_id:" + SERVER_CLIENT_ID + ":api_scope:" + SCOPE_EMAIL;
String code = null;
try {
code = GoogleAuthUtil.getToken(
LoginActivity.this, // Context context
Plus.AccountApi.getAccountName(mGoogleApiClient), // String accountName
scopes // String scope
);
} catch (IOException transientEx) {
Log.e(Constants.TAG, "IOException");
transientEx.printStackTrace();
// 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.
} catch (UserRecoverableAuthException e) {
Log.e(Constants.TAG, "UserRecoverableAuthException");
e.printStackTrace();
// Requesting an authorization code will always throw
// UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
// because the user must consent to offline access to their data. After
// consent is granted control is returned to your activity in onActivityResult
// and the second call to GoogleAuthUtil.getToken will succeed.
startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST_CODE);
} catch (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should not be
// retried.
Log.e(Constants.TAG, "GoogleAuthException");
authEx.printStackTrace();
} catch (Exception e) {
throw new RuntimeException(e);
}
Log.e(Constants.TAG, "ONE TIME CODE: " + code);
return code;
}
成功获取code后,发送到我的服务器进行认证。
这是服务器上的代码:
$code = $_POST['code'];
$client = new Google_Client();
$client->setApplicationName("my_app_name");
$client->setClientId('my_web_client_id'); // Web component's client id
$client->setClientSecret('client_secret'); // Web component's secret
$client->addScope("email");
$client->setAccessType("offline");
$client->authenticate($code);
...
问题是身份验证每 10-15 分钟只能进行一次。当尝试在 10-15 分钟内多次获取一次性代码时,我得到与上一次相同的代码(显然有问题。这种情况仅发生在 Android 客户端上,我收到此错误:Error fetching OAuth2 access token, message: 'invalid_grant: i'
)。在 SO 中找不到遇到同样问题的人。可能我做错了什么,但不知道它是什么......任何帮助将不胜感激。