Android Login-Аутентификатор учетной записи vs ручная аутентификация

Я собираюсь реализовать логин вместе с аутентификацией пользователя в моем приложении.

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

после googling вокруг, я собрал, что правильный способ сделать это на Android был с помощью аутентификатора учетной записи. Я видел несколько примеров его реализации, но я не понимаю преимущества этого способа? Это потому, что я могу иметь более одной учетной записи хранятся? Это из-за проблем с синхронизацией? Я был бы признателен, если бы кто-нибудь объяснил мне это. Это, вероятно, заставит меня лучше понять код для него и почему он делает то, что он есть.

3 ответов


у меня может быть более одной учетной записи?

да. Смотрите, как Google или Facebook сделать это.

это из-за проблем синхронизации?

да, вам нужна учетная запись, чтобы использовать механизм синхронизации, как SyncAdapter

почему вы должны использовать AccountAuthenticator?

  • поддержка механизма синхронизации фона, как SyncAdapter;

  • стандартный способ аутентификации пользователей;

  • поддержка различных токенов;

  • совместное использование учетной записи с различными привилегиями

что нужно делать?

1). Create Authenticator;

2). Create Activity логин пользователя;

3). Create Service общаться с счет.

термины.

AccountManager - он управляет учетной записью на устройстве. Запросить токены auth, которые вы должны использовать AccountManager.

AbstractAccountAuthenticator - компонент для работы с типами счетов. Он содержит всю логику по работе с учетной записи(авторизация, права доступа и т. д.) Один AbstractAccountAuthenticator может использоваться различными приложениями(например, учетная запись Google для Gmail, Календарь, диск так далее.)

AccountAuthenticatorActivity база Activity, для авторизации / создания учетной записи. AccountManager вызывает эту учетную запись, если необходимо идентифицировать учетную запись (токен не существует или истек)

как все это работает? Посмотрите на изображение ниже:

android account management diagram

действия.

1). Create Authenticator;

вам нужно продлить AbstractAccountAuthenticator и переопределить 7 методов:

  • Bundle editProperties(AccountAuthenticatorResponse response, String accountType) ссылке
  • Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) ссылке
  • Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) ссылке
  • Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) ссылке
  • String getAuthTokenLabel(String authTokenType) ссылке
  • Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) ссылке
  • Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) ссылке

пример:

public class LodossAuthenticator extends AbstractAccountAuthenticator {

    private static final String LOG_TAG = LodossAuthenticator.class.getSimpleName();

    private final Context mContext;

    public LodossAuthenticator(Context context) {
        super(context);
        mContext = context;
    }

    @Override
    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
        return null;
    }

    @Override
    public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
        final Intent intent = new Intent(mContext, CustomServerAuthenticatorSigninActivity.class);
        intent.putExtra(Config.ARG_ACCOUNT_TYPE, accountType);
        intent.putExtra(Config.ARG_AUTH_TYPE, authTokenType);
        intent.putExtra(Config.ARG_IS_ADDING_NEW_ACCOUNT, true);
        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);

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

    @Override
    public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
        return null;
    }

    @Override
    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
        // If the caller requested an authToken type we don't support, then
        // return an error
        if (!authTokenType.equals(AccountGeneral.AUTHTOKEN_TYPE_READ_ONLY) && !authTokenType.equals(AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS)) {
            final Bundle result = new Bundle();
            result.putString(AccountManager.KEY_ERROR_MESSAGE, "invalid authTokenType");
            return result;
        }

        // Extract the username and password from the Account Manager, and ask
        // the server for an appropriate AuthToken.
        final AccountManager am = AccountManager.get(mContext);
        String authToken = am.peekAuthToken(account, authTokenType);

        // Lets give another try to authenticate the user
        if (TextUtils.isEmpty(authToken)) {
            final String password = am.getPassword(account);
            if (password != null) {
                try {
                    authToken = sServerAuthenticate.userSignIn(account.name, password, authTokenType);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        // If we get an authToken - we return it
        if (!TextUtils.isEmpty(authToken)) {
            final Bundle result = new Bundle();
            result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
            result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
            result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
            return result;
        }

        // If we get here, then we couldn't access the user's password - so we
        // need to re-prompt them for their credentials. We do that by creating
        // an intent to display our AuthenticatorActivity.
        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
        intent.putExtra(com.lodoss.authlib.Config.ARG_ACCOUNT_TYPE, account.type);
        intent.putExtra(com.lodoss.authlib.Config.ARG_AUTH_TYPE, authTokenType);
        intent.putExtra(Config.ARG_ACCOUNT_NAME, account.name);
        final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);
    return bundle;
    }

    @Override
    public String getAuthTokenLabel(String authTokenType) {
        if (AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS.equals(authTokenType))
            return AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS_LABEL;
        else if (AccountGeneral.AUTHTOKEN_TYPE_READ_ONLY.equals(authTokenType))
            return AccountGeneral.AUTHTOKEN_TYPE_READ_ONLY_LABEL;
        else
            return authTokenType + " (Label)";
    }

    @Override
    public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
        return null;
    }

    @Override
    public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
        final Bundle result = new Bundle();
        result.putBoolean(KEY_BOOLEAN_RESULT, false);
        return result;
    }
}

объяснение:

Итак, вы нужно увидеть только 2 метода:addAccount, getAuthToken.

на addAccount я добавил некоторые параметры конфигурации, которые будут использоваться my Activity для входа пользователей. Главное здесь -intent.putExtra(Config.ARG_ACCOUNT_TYPE, accountType); - здесь следует указать тип учетной записи. Другие манипуляции не нужны.

на getAuthToken - читать комментарии, пожалуйста. Я скопировал этот метод из UdinicAuthenticator.java

кроме того, вам понадобятся следующие разрешения в ваш AndroidManifest.XML-код:

<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />

резюме из методов addAccount и getAuthToken

попробуйте получить токен, если токен существует, верните результат, иначе вы увидите Activity разрешение

2). Create Activity логин пользователя;

посмотреть AuthenticatorActivity

краткое описание: Создайте форму с идентификатором пользователя и паролем. Используя данные UserId & Password, получите токен аутентификации с сервера, а затем выполните следующий шаг:

mAccountManager.addAccountExplicitly(account, accountPassword, null);
mAccountManager.setAuthToken(account, authtokenType, authtoken);

3). Создать Service для связи с учетной записью.

посмотреть UdinicAuthenticatorService

не забудьте добавить эту строку в AndroidManifest.xml to Service:

    <intent-filter>
        <action android:name="android.accounts.AccountAuthenticator" />
    </intent-filter>
    <meta-data android:name="android.accounts.AccountAuthenticator"
               android:resource="@xml/authenticator" />

а также в res/xml добавить файл authenticator.xml:

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
                       android:accountType="com.mediamanagment.app"
                       android:icon="@drawable/ic_launcher"
                       android:smallIcon="@drawable/ic_launcher"
                       android:label="@string/authenticator_label"/>

вот и все. Вы можете использовать AccountAuthenticator.

для исходных материалов благодаря


на AccountManager хорошо по следующим причинам:

  • во-первых, чтобы сохранить несколько имен учетных записей с различными уровнями доступа к функциям приложения под одним типом учетной записи. Например, в приложении для потоковой передачи видео у одного может быть два имени учетной записи: одно с демонстрационным доступом к ограниченному числу видео, а другое с полным месячным доступом ко всем видео. Это не главная причина для использования Accounts, однако, так как вы можете легко управлять этим в своем приложении без необходимость в этом причудливом виде Accounts вещь... .
  • другое преимущество использования Accounts это избавиться от традиционной авторизации с именем пользователя и паролем каждый раз, когда пользователь запрашивает авторизованную функцию, потому что аутентификация происходит в фоновом режиме, и пользователь запрашивает свой пароль только в определенном состоянии, которое я получу к нему позже.
  • С помощью Accounts функция в android также устраняет необходимость определения собственного тип счета. Вероятно, вы столкнулись с приложениями, использующими учетные записи Google для авторизации, что экономит хлопоты создания новой учетной записи и запоминания ее учетных данных для пользователя.
  • Accounts можно добавить независимо через Настройки → Учетные записи
  • кросс-платформенный авторизации пользователей можно легко управлять с помощью Accounts. Например, клиент может получить доступ к защищенному материалу одновременно на своем устройстве android и ПК без необходимости повторного входы.
  • С точки зрения безопасности, использование одного и того же пароля в каждом запросе на сервер позволяет подслушивать в небезопасных соединениях. Шифрование пароля здесь недостаточно для предотвращения кражи пароля.
  • наконец, важная причина для использования Accounts функция в android, чтобы разделить две стороны, участвующие в любом бизнесе зависит от Accounts, так называемый Аутентификатор и владелец ресурса, без ущерба для клиента (пользователя) с полномочия. Термины могут показаться довольно расплывчатыми, но не сдавайтесь, пока не прочтете следующий абзац ...

позвольте мне подробно остановиться на последнем с примером потокового видео приложения. Компания A является держателем бизнеса потокового видео в контракте с компанией B, чтобы предоставить своим определенным членам премиум-услуги потокового видео. Компания B использует метод имени пользователя и пароля для распознавания своего пользователя. Для компании A признать премиум-членов B, один из способов будет чтобы получить список из них от B и использовать аналогичный механизм сопоставления имени пользователя/пароля. Таким образом, Аутентификатор и владелец ресурса одинаковы (компания A). Помимо обязанности пользователей запоминать второй пароль, весьма вероятно, что они установили тот же пароль, что и профиль их компании B для использования услуг от A. Это, очевидно, не выгодно.

чтобы устранить вышеуказанные недостатки, был введен OAuth. Как открытый стандарт для авторизация в приведенном выше примере OAuth требует, чтобы авторизация была выполнена компанией B (Аутентификатор) путем выдачи некоторого токена, называемого токеном доступа для соответствующих пользователей (третья сторона), а затем предоставления компании A (владелец ресурса) токена. Таким образом, отсутствие токена означает отсутствие права.

я более подробно об этом и более на AccountManager мой сайт здесь


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