AccountManager: когда установить результат? - PullRequest
0 голосов
/ 31 мая 2018

Контекст

Мое приложение хранит только пользователя / пароль.Маркеры не используются.

Вопрос 1

Методы setAccountAuthenticatorResult(Bundle) и onResult(Bundle) предназначены для уведомления AbstractAccountAuthenticator о результате, но у меня есть проект, работающий без них, для чего они нужны?

Вопрос 2

Что такое onRequestContinued() для?

Вопрос 3

Когда addAccount закончится и будет создана учетная запись, следует ли вызывать onActivityResult на Activity, который ее вызвал?

Вопрос 4

Если Intent возвращается с ключом AccountManager.KEY_INTENT в addAccount реализации, начнется AbstractAccountAuthenticatorIntent.Я заметил, что многие разработчики добавляют дополнения.Кто их получает?

public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException
{
    Intent intent = new Intent(mContext, AuthenticatorActivity.class);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);

    intent.putExtra(AuthenticatorActivity.ARG_ACCOUNT_TYPE, accountType);     // <-- this
    intent.putExtra(AuthenticatorActivity.ARG_AUTH_TYPE, authTokenType);      // <-- this
    intent.putExtra(AuthenticatorActivity.ARG_IS_ADDING_NEW_ACCOUNT, true);   // <-- this


    Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);

    return bundle;
}

Ответы

Крис Ларсон :

Спасибо за ответ.Я думаю, что мы можем использовать AccountManager неправильно, если честно.

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

Когда каждое приложение запускается, они пытаются получить Account.Если Account не существует, они запускают страницу входа в нашу Service, вызывая AccountManager.addAccount(...).

После успешного входа (через веб-службы) мы делаем его доступным для других приложений с * 1074.*.Не устанавливая результат после него, не влияет на результат.

Как это влияет на AccountManager?Правильный ли этот подход?

Ответы [ 2 ]

0 голосов
/ 09 июня 2018

Методы setAccountAuthenticatorResult (Bundle) и onResult (Bundle) предназначены для уведомления AbstractAccountAuthenticator о результате, но у меня есть проект, работающий без них, для чего они нужны?

Теметоды (а также onError) должны передавать результат тому, кто может его ждать, например, взгляните на AccountManager.getAuthToken(...) и многие другие, которые позволяют вам указать AccountManagerCallback<Bundle>.Это где ваш результат будет передан.null допустимо для обратного вызова, поэтому, если вы не структурируете свое приложение вокруг результата, оно будет работать без него.

AccountAuthenticatorResponse.onResult(Bundle) и onError(...) гораздо важнее, если вы реализуете getAuthToken, где этокак вы можете вернуть токен доступа из асинхронного внутреннего вызова (например, обновление токена).

Что такое onRequestContinued () для?

Очень мало информации (читает: нет) доступно.Единственный раз, когда он привык, я смог найти это в AccountManagerService, где счетчик увеличивался для целей регистрации.Я не думаю, что в данный момент это что-то делает.

Когда addAccount завершит работу и будет создана учетная запись, должен ли onActivityResult вызываться для действия, которое его вызвало?

Должно работать до тех пор, пока вы используете startActivityForResult(..)

. Если Intent возвращается с ключом AccountManager.KEY_INTENT в реализации addAccount, AbstractAccountAuthenticator запустит Intent.Я заметил, что многие разработчики добавляют дополнения.Кто их получит?

Как уже упоминалось Крисом, вы можете вернуть Намерение, которое запускает вашу Активность, и передать любые дополнительные материалы, которые вам могут понадобиться.


На неродственной ноте: Вы действительно должны стараться не хранить пароли в виде простого текста.Несмотря на то, что AccountManager говорит setPassword(), он не защищен и, следовательно, не защищен.

0 голосов
/ 04 июня 2018

РЕДАКТИРОВАТЬ: я просто опишу, как - после долгих мучений - я реализовал сервис аутентификации для нашего приложения.

Вы сказали, что у вас есть Service для аутентификатора.Я предполагаю, что вы сделали это предписанным способом: объявите службу в своем манифесте, которая ссылается на ваш класс, подклассы которого android.accounts.AbstractAccountAuthenticator.Запись манифеста также ссылается на файл XML с тегом account-authenticator, который объявляет тип вашей учетной записи, а также имя и значки, которые будут использоваться настройками |Страница аккаунтов.Все это задокументировано.

Для нашего приложения я хотел, чтобы последний зарегистрированный пользователь автоматически входил в систему, пока он не выберет «Выход» в навигационной панели.Для этого имя пользователя будет сохранено в SharedPreferences для приложения.

Так что если SharedPreferences действительно не имеет имя пользователя, приложение вызывает AccountManager.newChooseAccountIntent() для нашего пользовательскоготип учетной записи, затем вызывает startActivityForResult с намерением, которое было возвращено.Если пользователь выбирает «Добавить новую учетную запись», то на аутентификаторе будет вызываться addAccount(), как описано ниже.

Наша деятельность по аутентификации имеет не только пользовательский интерфейс для входа в систему с именем пользователя / паролем, но также сброс пароля и новую пробную учетную запись.создание, поэтому есть много движущихся частей.Когда пользователь вводит имя пользователя / пароль и нажимает кнопку «Вход», приложение проходит аутентификацию на нашем сервере.В случае успеха приложение вызывает AccountManager.addAccountExplicitly() для этого имени пользователя.

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

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

С выбранной / известной учетной записью, теперь приложение может аутентифицироваться.Он вызывает peekAuthToken(), чтобы увидеть, был ли зарегистрирован токен, и invalidateAuthToken(), если он был.Это делается для того, чтобы при вызове приложением getAuthToken() в диспетчере учетных записей оно заставляло диспетчера учетных записей вызывать getAuthToken() в аутентификаторе приложения для аутентификации на сервере.Поскольку сервер не возвращает токены, мы используем фиктивные токены, и поэтому они каждый раз аннулируются.

Теперь интересная часть всего этого заключается в том, что если пользователь выбирает учетную запись, которая уже была зарегистрирована, онне будет аутентифицирован, тогда как если они выбрали Добавить новую учетную запись и операция прошла успешно, новая учетная запись будет аутентифицирована.Так что просто имейте в виду, что если вы заметили, что вход в новую учетную запись вызывает два обращения к вашему серверу аутентификации, теперь вы знаете, почему.(У меня есть некоторая логика с использованием setUserData() в учетной записи для обозначения предварительной аутентификации, но похоже, что я забыл завершить эту функцию. Хммм.)


Давайте начнем с некоторого фона, чтобы уточнитьвещи.

У вас есть некоторый подкласс AbstractAccountAuthenticator.Вы создали этот класс для ответа на запросы аутентификации для типа учетной записи, для которой он был зарегистрирован.Об этом классе следует помнить, что платформа AccountManager всегда является компонентом, с которым ваше приложение будет взаимодействовать;Ваше приложение никогда не будет взаимодействовать напрямую с этим классом.Таким образом, в некотором смысле AccountManager является клиентом вашей службы аутентификации.Работа, которую выполняет аутентификатор, - это работа в фоновом потоке.

Теперь часть работы, которую должна выполнять служба аутентификации, - это взаимодействие с пользователем, запрос имени пользователя, пароля, идентификатора отпечатка пальца, умного.карты и т. д. Итак, давайте предположим, что у вас есть AuthenticatorActivity, который делает эту работу.Как правило, вы будете подкласс android.accounts.AccountAuthenticatorActivity для этого.Этот класс деятельности действительно ничего особенного.Единственное, что он делает, - это ожидает ссылку на AccountAuthenticatorResponse при его запуске, а затем вызывает метод onResult() этого ответа при завершении действия.

Приложение, над которым я работаю, похоже на ваше в этомтокен не возвращается из службы аутентификации.Я все еще реализовал getAuthToken по двум причинам:

  • в соответствии с рабочим процессом, предписанным Google.
  • , чтобы упростить возврат реального токена, если / когда мы улучшаем нашу службу аутентификации для возврата токена.

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

  • В вашем приложении реализован интерфейс AccountManagerCallback, чтобы получать асинхронные сообщения от AccountManager.
  • Давайте предположим, что ваше приложение сохранило имя пользователя для аутентификации.Ваше приложение создает объект Account с этим именем пользователя.
  • При желании ваше приложение может вызвать AccountManager.getAccountsByType(), чтобы убедиться, что учетная запись существует.
  • Ваше приложение вызывает AccountManager.getAuthToken() для этой учетной записи.
  • AccountManager видит, что ваш аутентификатор зарегистрирован для этого типа учетной записи, и вызывает метод аутентификатора getAuthToken.
  • Метод getAuthToken свяжется с вашим сервером аутентификации и получит ответ.
  • В случае успеха ваш аутентификатор возвращает (фиктивный) токен авторизации.

Если вход в систему не удастся, тогда все становится интересным.

  • Так как вашАутентификатор не возвращает токен авторизации, он должен вернуть намерение запустить ваш AuthenticatorActivity, чтобы пользователь мог повторно пройти аутентификацию.

  • AccountManager использует ваше намерение запустить вашAuthenticatorActivity.Как часть запроса, он получит ссылку на AccountAuthenticatorResponse, который потребуется позже.

  • Ваш AuthenticatorActivity взаимодействует с пользователем, получает имя пользователя / пароль, связывается с вашим сервером, получаетответ.Допустим, аутентификация прошла успешно.
  • Ваша деятельность будет завершена, вызовет onResult метод AccountAuthenticatorResponse, который ей был дан.
  • AccountManager при получении уведомления от объекта ответа будетвызовите метод обратного вызова с результатами.

Таким образом, мы можем ответить на ваши вопросы:

Методы setAccountAuthenticatorResult(Bundle) и onResult(Bundle) предназначены для уведомления AbstractAccountAuthenticator о результате, но у меня есть проект, работающий без них, для чего они нужны?

Вернее, они предназначены для уведомления AccountManager о результате.Вы уверены, что это работает?Вы пытались войти с неверным именем пользователя или паролем?AccountManager будет предполагать, что аутентификация была отменена, если не получено иное уведомление.

Для чего нужен onRequestContinued()?

У меня нет точного ответа.Я предполагаю, что это должно как-то синхронизировать AccountManager с тем, что происходит с пользовательским интерфейсом в отношении аутентификации.

Если Intent возвращается с ключом AccountManager.KEY_INTENT в addAccount реализация, AbstractAccountAuthenticator запустит Намерение.Я заметил, что многие разработчики добавляют дополнения.Кто их получает?

Ответ: да.Это намерение пойдет в AuthenticatorActivity, которое вы создали для обработки аутентификации, поэтому любые данные, необходимые вашей деятельности для выполнения аутентификации, должны быть переданы вместе с этими дополнениями.

Когда addAccount закончится исозданная учетная запись, должна ли onActivityResult вызываться на Activity, которая ее инициировала?

Вариант использования для этого - когда ваше приложение вызывает AccountManager.newChooseAccountIntent(), затем вызывает startActivityForResult() с полученным намерением,Затем запускается действие AccountManager «Выбрать учетную запись».

Теперь, поскольку «добавить новую учетную запись» является опцией в пользовательском интерфейсе «Выбор учетной записи», AccountManager будет вызывать addAccount() вашего аутентификатора.метод, когда эта опция выбрана.Затем ваш аутентификатор возвращает Bundle, как описано в AbstractAccountAuthenticator документах, обратно к AccountManager.После этого действие «выбрать учетную запись» завершится, и вы позвоните по номеру onActivityResult().

Надеюсь, вы начинаете понимать, что AccountManager действует как посредник между вашим приложением и вашими компонентами аутентификатора.Чтобы сделать это более понятным, учтите, что вы можете упаковать эти компоненты таким образом, чтобы другие приложения могли использовать их для аутентификации в вашей службе, не зная каких-либо подробностей.Если вы создали свой собственный тип учетной записи, вы можете вызвать вашу аутентификацию прямо из меню Настройки |Страница аккаунтов устройства.Это хороший тест, чтобы проверить, правильно ли реализован ваш метод addAccount().

...