在 Android 上为 Google+ 重新生成 "one time authorization code"

Regeneration of "one time authorization code" for Google+ on Android

我正在根据以下内容通过 Google+ 进行身份验证: https://developers.google.com/+/mobile/android/sign-in

这个过程的大部分看起来都很好。我遇到的问题是我们需要获得 "one-time authorization code" 以便我们的后端服务器可以在用户许可的情况下代表用户执行某些请求。 "Enable server-side api access for your app" 部分对此进行了介绍。但是,由于多种原因,我们的服务器 可以 导致登录失败,即使授权码有效(例如,用户没有对应于 google+ 我们服务器上的帐户,在这种情况下他们可以创建一个)。

如果发生这种情况,我们可能需要他们稍后再次登录。不过,我发现的是,当我使用 google+ 执行第二次登录时,它会给我 相同的授权码 ,即使它已经被我们使用过服务器。我试过断开连接并重新连接到 google 客户端 api,然后调用 GoogleApiClient.clearDefaultAccountAndReconnect(),但无论我做什么,我似乎都得到了相同的授权码。这当然会在尝试使用它时被服务器拒绝,因为它已经被使用过。

我想知道我做错了什么。我有以下方法,它在初始身份验证过程中被调用,然后如果从我们的服务器检测到 500 的响应状态(表明之前的调用失败,可能是因为代码已被使用)再次调用:

  private void dispatchGooglePlusAuthCodeAcquisition() {
    AsyncTask<Void, Void, String> authAcquisition = new AsyncTask<Void, Void, String>() {
      @Override
      protected String doInBackground(Void... params) {
        Bundle authPreferences = new Bundle();
        mUserPermissionNeededForAuthCode = false;
        authPreferences.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
                                "");
        String scopesString = Scopes.PROFILE;
        WhenIWorkApplication app = (WhenIWorkApplication)WhenIWorkApplication.getInstance();
        String serverClientID = app.getGoogleOAuthClientIDForPersonalServer();
        String scope = "oauth2:server:client_id:" + serverClientID + ":api_scope:" + scopesString;
        String code = null;
        authPreferences.putBoolean(GoogleAuthUtil.KEY_SUPPRESS_PROGRESS_SCREEN, true);

        try {
          code = GoogleAuthUtil.getToken(
            mActivity,
            Plus.AccountApi.getAccountName(mGoogleApiClient),
            scope,
            authPreferences
          );
        } 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.
          Log.d(LOGTAG, "Encountered an IOException while trying to login to Google+."
                                   + " We'll need to try again at a later time.");
        } catch (UserRecoverableAuthException e) {
          mUserPermissionNeededForAuthCode = true;
          // 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.
          if (!mGooglePlusPermissionActivityStarted) {
            mGooglePlusPermissionActivityStarted = true;
            mActivity.startActivityForResult(e.getIntent(), RESULT_CODE_AUTH_CODE);
          }
        } catch (GoogleAuthException authEx) {
          // Failure. The call is not expected to ever succeed so it should not be
          // retried.
          Log.e(LOGTAG, "Unable to authenticate to Google+. Call will likely never"
                                   + " succeed, so bailing.", authEx);
        }

        return code;
      }

      @Override
      protected void onPostExecute(String aResult) {
        if (aResult != null) {
          // We retrieved an authorization code successfully.
          if (mAPIAccessListener != null) {
            mAPIAccessListener.onAuthorizationCodeGranted(aResult);
          }
        } else if (!mUserPermissionNeededForAuthCode) {
          // If this is the case, then we didn't get authorization from the user, or something
          // else happened.
          if (mAPIAccessListener != null) {
            mAPIAccessListener.onAuthorizationFailed();
          }

          Log.d(LOGTAG, "Unable to login because authorization code retrieved was null");
        }
      }
    };

    authAcquisition.execute();

所以,这个问题的答案比我想象的要简单得多。显然,在 GoogleAuthUtil class:

上有一个 clearToken() 方法

http://developer.android.com/reference/com/google/android/gms/auth/GoogleAuthUtil.html#clearToken%28android.content.Context,%20java.lang.String%29

public static void clearToken (Context context, String token)

Clear the specified token in local cache with respect to the Context. Note that the context must be the same as that used to initialize the token in a previous call to getToken(Context, String, String) or getToken(Context, String, String, Bundle).

Parameters

context Context of the token.
token The token to clear.

Throws

GooglePlayServicesAvailabilityException
GoogleAuthException
IOException

在尝试重新验证之前调用此方法会导致 Google 生成新的一次性授权令牌。