【问题标题】:Regeneration of "one time authorization code" for Google+ on Android为 Android 上的 Google+ 重新生成“一次性授权码”
【发布时间】:2015-06-27 19:31:07
【问题描述】:

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

这个过程的大部分看起来都很好。我遇到的问题是我们需要获得一个“一次性授权码”,以便我们的后端服务器可以在用户许可的情况下代表用户执行某些请求。这在“为您的应用程序启用服务器端 api 访问”部分中进行了介绍。但是,出于多种原因,我们的服务器可能导致登录失败,即使授权代码有效(例如,用户在我们的服务器上还没有与 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();

【问题讨论】:

    标签: android authentication google-plus google-client


    【解决方案1】:

    所以,这个问题的答案比我想象的要简单得多。显然,GoogleAuthUtil 类上有一个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(上下文上下文,字符串令牌)

    针对上下文清除本地缓存中的指定令牌。请注意,上下文必须与之前调用 getToken(Context, String, String) 或 getToken(Context, String, String, Bundle) 时用于初始化令牌的上下文相同。

    参数

    context 令牌的上下文。
    token 要清除的令牌。

    投掷

    GooglePlayServicesAvailabilityException
    GoogleAuthException
    IOException

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

    【讨论】:

    • 这就是我正在做的,但我仍然得到相同的授权码 10 分钟。这是否立即为您返回了新的授权码?
    • @Jonathan 所以,我要做的是我有一个GooglePlusAuthUtil 类,我将授权令牌作为成员变量存储在其中。如果授权令牌是非空的(也就是说,我已经看到了一个令牌),我调用clearToken(),然后我再次调用getToken() 并将结果存储在成员变量中。这确实为我重新生成了令牌,是的。
    • @Jonathan 抱歉,我忘了提到一个关键部分——您必须使用 clearToken() 方法调用发送令牌。您是否有可能在clearToken() 方法完成之前尝试调用getToken()(即以异步方式)?
    • @jwir3 我使用这种方法成功地重新生成了我的授权码。但是,我还发现这样做会在调用 getToken() 时导致 UserRecoverableAuthException,并且我将再次批准同意对话框。理想情况下,我希望这是在用户第一次签署并同意后单击登录。有什么办法吗?
    猜你喜欢
    • 1970-01-01
    • 2014-03-03
    • 1970-01-01
    • 2014-02-18
    • 1970-01-01
    • 2011-05-07
    • 2021-12-13
    • 1970-01-01
    • 2017-04-20
    相关资源
    最近更新 更多