在安卓设备上对于Google+的“一次性授权码”的重新生成

5
我正在使用 Google+ 进行身份验证,参考以下链接: https://developers.google.com/+/mobile/android/sign-in 这个过程中大部分看起来没问题。但我遇到的问题是,我们需要获取“一次性授权码”,以便我们的后端服务器可以代表用户执行某些请求,并得到他们的允许。这在“启用应用的服务器端 API 访问”一节中有介绍。然而,由于种种原因,即使授权码有效(例如,该用户还没有对应于我们服务器上的 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();
1个回答

3
所以,这个答案比我想象的要简单得多。显然,GoogleAuthUtil类上有一个clearToken()方法: http://developer.android.com/reference/com/google/android/gms/auth/GoogleAuthUtil.html#clearToken%28android.content.Context,%20java.lang.String%29 该方法可以清除本地缓存中关于指定token的信息,需要传入相应的context参数。注意,该context必须与之前调用getToken(Context, String, String)或getToken(Context, String, String, Bundle)方法时使用的context相同。 参数:
context - token相关联的context对象
token - 要清除的token 抛出异常:
GooglePlayServicesAvailabilityException
GoogleAuthException
IOException 在尝试重新授权之前调用此方法会导致Google生成新的一次性授权标记。

这就是我正在做的事情,但我仍然得到相同的授权码长达10分钟。这是否立即为您返回了新的授权码? - Jonathan
@Jonathan 所以,我的做法是创建一个名为 GooglePlusAuthUtil 的类,并将授权令牌存储为成员变量。如果授权令牌不为空(也就是说,我已经看到过一次令牌通过网络传输),我会调用 clearToken() 方法,然后再次调用 getToken() 方法并将结果存储在成员变量中。这确实为我重新生成了令牌。 - jwir3
@Jonathan 抱歉,我忘记提到一个关键部分 - 你必须在 clearToken() 方法调用时发送令牌。你是否尝试在 clearToken() 方法完成之前(即以异步方式)调用 getToken() - jwir3
1
我通过这种方法成功地重新生成了我的授权码。但是,我还发现这样做会在调用getToken()时导致UserRecoverableAuthException,并且我需要再次批准同意对话框。理想情况下,在用户第一次登录并给出同意后,我希望这只是一个单击登录。有什么办法解决这个问题吗? - waynesford

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接