Почему AccountAuthenticator#getAuthToken() не вызывается?

Я создал свой собственный аутентификатор учетной записи Android, расширив AbstractAccountAuthenticator и реализовав addAccount() и getAuthToken(). Некоторые методы в нем вызываются AccountManager, а другие нет. .

Это прекрасно работает:

AccountManager#addAccount()

AccountManager accountManager = AccountManager.get(activity);
accountManager.addAccount(MyAccountAuthenticator.ACCOUNT_TYPE,
    MyAccountAuthenticator.AUTHTOKEN_TYPE_FULL_ACCESS, null, null,
    activity, callback, null);

Проблема возникает, когда я вызываю AccountManager#getAuthToken() в моем Activity. AccountManager не вызывает метод getAuthToken(), который я определяю в моем AccountAuthenticator. Он вызывает какой-то другой метод по умолчанию, который только проверяет наличие authToken перед запуском AuthenticatorActivity.

Это не работает. Он не вызывает мой метод getAuthToken():

AccountManager#getAuthToken()

AccountManager accountManager = AccountManager.get(activity);
accountManager.getAuthToken(
        mAccount, MyAccountAuthenticator.AUTHTOKEN_TYPE_FULL_ACCESS, null,
        activity, callback, handler);

AuthenticatorService

Я создал свой сервис и определил onBind(). addAccount() иначе работать не должно.

public IBinder onBind(Intent intent) {
    return intent.getAction().equals(ACTION_AUTHENTICATOR_INTENT) ? new MyAccountAuthenticator(this).getIBinder() : null;
}

EDIT: я вызываю addAccountExplicitly в MyAuthenticatorActivity после того, как приложение возвращает токен авторизации для пользователя.

Фрагмент урока MyAuthenticatorActivity extends AccountAuthenticatorActivity:

if (getIntent().getBooleanExtra(KEY_IS_ADDING_NEW_ACCOUNT, false)) {
    // Creating the account on the device and setting the auth token we recieved
    accountManager.addAccountExplicitly(account, null, null);
}

person Austyn Mahoney    schedule 08.01.2014    source источник
comment
Вы когда-нибудь использовали addAccountExplicitly в своей деятельности?   -  person Tom G    schedule 31.01.2014
comment
Да, я называю это в своем подклассе AccountAuthenticatorActivity. Я добавил это в EDIT в вопросе.   -  person Austyn Mahoney    schedule 31.01.2014
comment
Если результатом вызова getAuthToken является запуск вашей активности входа в систему, то вызывается ваш аутентификатор - у Android нет другого способа определить, какую активность запускать, кроме того, что вы возвращаете как Intent. Я заметил, что вы добавляете учетную запись с нулевым паролем. Возможно, ваша реализация замкнется, если найдет нулевой проход? Опубликуйте тело getAuthToken из вашего аутентификатора.   -  person Tom G    schedule 31.01.2014
comment
Как я упоминал в своем вопросе, getAuthToken() даже не вызывается, когда существует существующий набор токенов аутентификации. Он обходит вызов и просто возвращает токен аутентификации, чего я не ожидал. Как я интерпретировал документацию, она все равно должна вызывать мой метод. Затем я могу решить, хочу ли я вернуть существующий токен или получить новый (перед возвратом я проверяю, не истек ли срок действия токена авторизации).   -  person Austyn Mahoney    schedule 01.02.2014
comment
Пароль нулевой, потому что я использую токены носителя OAuth. Пароль устанавливать не нужно, и я никогда не использую это поле. Метод getAuthToken отлично работает, когда он действительно вызывается, нет необходимости видеть там исходный код.   -  person Austyn Mahoney    schedule 01.02.2014
comment
Мой ответ прояснил ситуацию?   -  person Tom G    schedule 03.02.2014


Ответы (2)


Ваш комментарий очень многое прояснил: если вы установите токен авторизации для учетной записи, то ваш метод getAuthToken не будет вызываться до тех пор, пока токен не станет недействительным. Обычно это делается путем вызова invalidateAuthToken. при получении 401 или 403 или чего-то еще от веб-службы.

Из Javadoc для методов getAuthToken:

Если ранее сгенерированный токен аутентификации кэшируется для этой учетной записи и типа, он возвращается. В противном случае, если сохраненный пароль доступен, он отправляется на сервер для создания нового токена аутентификации. В противном случае пользователю будет предложено ввести пароль.

Поскольку ваш токен находится в кеше, он возвращается напрямую, и ваш аутентификатор не консультируется.

person Tom G    schedule 31.01.2014
comment
Спасибо. Документы очень неоднозначно относятся к тому, когда он вызывает аутентификатор, а когда просто вызывает свой собственный код. Я думал, что мой аутентификатор должен реализовать функциональность, описанную в вашей цитате. - person Austyn Mahoney; 06.02.2014
comment
Нет проблем — я согласен, что документы аутентификатора, как правило, довольно плохие. - person Tom G; 06.02.2014
comment
Более того, если getAuthToken() успешно возвратил KEY_AUTHTOKEN один раз, он автоматически кэшируется (даже без каких-либо вызовов AccountManager.setAuthToken() в вашем приложении). Таким образом, все последующие вызовы AccountManager.getAuthToken() не приведут к вызову Authenticator.getAuthToken(), а просто немедленно вернут токен String. Протестировано на Android 4.3 Samsung Note 2. - person Deepscorn; 23.06.2015
comment
Спасибо вам, ребята! Так зачем же там АД peekAuthToken(), если вызов getAuthToken() уже делает все за вас? Я вызывал setAuthToken вне Authenticator, затем в моем getAuthToken я вызываю peekAuthToken, чтобы проверить, есть ли у нас кэшированный authToken... но он не вызывается, потому что getAuthToken уже выполняет эту работу за вас, верно? - person Angelo; 30.09.2016
comment
это сделало мой день!! Это предложение - если вы установите токен авторизации для учетной записи, то ваш метод getAuthToken не будет вызываться до тех пор, пока токен не будет признан недействительным - заставило меня понять все - person Apperside; 19.02.2017
comment
Это предложение из документации не имеет никакого смысла. Поскольку он возвращает кешированный токен, но НЕ генерирует новый токен, если токен недействителен, мы должны сделать это сами. Это глупо, потому что я хотел бы проверить дату истечения срока действия, чтобы мне не нужно было делать сетевой вызов, чтобы выяснить, истек ли срок действия токена. Но это не так удобно кодировать, если я не могу закодировать его внутри getAuthToken() - person Evren Yurtesen; 10.03.2018

для вызова AuthenticatorActivity в методе AccountManager#getAuthToken вы должны отправить намерение в действие с помощью метода посылки, например:

    final Intent intent = new Intent(mContext, LoginActivity.class);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, accountAuthenticatorResponse);
    intent.putExtra(LoginActivity.ARG_ACCOUNT_TYPE, account.type);
    intent.putExtra(LoginActivity.ARG_AUTH_TYPE, authTokenType);
    intent.putExtra(LoginActivity.ARG_ACCOUNT_NAME, account.name);
    final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);
person Zia Ulhaq    schedule 20.09.2014
comment
Это вообще не отвечает на вопрос. - person Austyn Mahoney; 20.09.2014