РЕДАКТИРОВАТЬ: я просто опишу, как - после долгих мучений - я реализовал сервис аутентификации для нашего приложения.
Вы сказали, что у вас есть 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()
.