Регенерация одноразового кода авторизации для Google+ на Android

Я работаю с аутентификацией через Google+ в соответствии со следующим: https://developers.google.com/+/mobile/android/sign-in

Большая часть этого процесса выглядит нормально. Проблема, с которой я столкнулся, заключается в том, что нам нужно получить «одноразовый код авторизации», чтобы наши внутренние серверы могли выполнять определенные запросы от имени пользователя с его разрешения. Это описано в разделе «Включение доступа API на стороне сервера для вашего приложения». Однако по ряду причин наши серверы могут привести к сбою входа в систему, даже если код авторизации действителен (например, у пользователя еще нет учетной записи, соответствующей учетной записи google+ на наших серверах). , и в этом случае они могут сделать один).

Если это произойдет, нам может понадобиться, чтобы они снова вошли в систему позже. Однако я обнаружил, что когда я выполняю второй вход в систему с помощью Google+, он дает мне тот же код авторизации, даже если он уже использовался нашими серверами. Я пытался отключить и снова подключиться к API-интерфейсу клиента Google и вызвать 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();

person jwir3    schedule 20.04.2015    source источник


Ответы (1)


Итак, ответ на этот вопрос был намного проще, чем я себе представлял. Судя по всему, в классе GoogleAuthUtil есть метод aclearToken():

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

public static void clearToken (контекст контекста, токен String)

Очистить указанный токен в локальном кеше относительно контекста. Обратите внимание, что контекст должен быть таким же, как тот, который использовался для инициализации токена в предыдущем вызове getToken(Context, String, String) или getToken(Context, String, String, Bundle).

Параметры

context Контекст маркера.
token Маркер для очистки.

Броски

GooglePlayServicesAvailabilityException
GoogleAuthException
IOException

Вызов этого метода перед повторной аутентификацией приводит к тому, что Google создает новый одноразовый токен авторизации.

person jwir3    schedule 01.05.2015
comment
Я так и делаю, но все равно получаю тот же код авторизации на 10 минут. Это немедленно вернуло вам новый код авторизации? - person Jonathan; 26.05.2015
comment
@Jonathan Итак, что я делаю, так это то, что у меня есть класс GooglePlusAuthUtil, в котором я храню токен авторизации в качестве переменной-члена. Если токен авторизации не нулевой (то есть я уже видел, как токен попадал в сеть), я вызываю clearToken(), а затем снова вызываю getToken() и сохраняю результат в переменной-члене. Это восстанавливает токен для меня, да. - person jwir3; 26.05.2015
comment
@Jonathan Извините, я забыл упомянуть важную часть - вы должны отправить токен с вызовом метода clearToken(). Возможно ли, что вы пытаетесь вызвать getToken() до завершения метода clearToken() (т. е. асинхронным способом)? - person jwir3; 26.05.2015
comment
@jwir3 Я успешно регенерирую свой код авторизации, используя этот метод. Но я также обнаружил, что выполнение этого таким образом приведет к UserRecoverableAuthException при вызове getToken(), и мне придется снова одобрить диалоговое окно согласия. В идеале я бы хотел, чтобы это был вход в один клик после того, как пользователь подписал и дал согласие в первый раз. Как-нибудь обойти это? - person waynesford; 03.08.2015