Inicio de sesión de Android-Autenticador de cuentas vs Autenticación manual


Estoy a punto de implementar el inicio de sesión junto con la autenticación de usuario en mi aplicación.

Mi primera idea fue hacerlo manualmente, registrar el nombre de usuario y la contraseña con el servidor, obtener el token de autenticación, guardarlo y usarlo en solicitudes posteriores.

Después de buscar en Google, me di cuenta de que la forma correcta de hacerlo en Android estaba utilizando Account Authenticator. He visto algunos ejemplos de su implementación, pero no entiendo la ventaja de hacerlo de esta manera. Es porque puedo tener más de una cuenta almacenados? ¿Es por problemas de sincronización? Agradecería que alguien me explicara esto. Probablemente me haría entender mejor el código y por qué está haciendo lo que es.

Author: Daniel Julio, 2015-08-10

3 answers

Puedo tener más de una cuenta almacenados?

Sí. Ver cómo Google o Facebook hacerlo.

¿Se debe a problemas de sincronización?

Sí, necesita una cuenta para usar un mecanismo de sincronización como SyncAdapter

¿Por qué debe usar AccountAuthenticator?

  • Soporte de mecanismo de sincronización en segundo plano como SyncAdapter;

  • Forma estándar de autenticar usuarios;

  • Soporta diferentes tokens;

  • Compartir Cuenta con diferentes privilegios

¿Qué necesitas hacer?

1). Crear Authenticator;

2). Crear Activity para el Inicio de sesión del usuario;

3). Crear Service para comunicarse con la cuenta.

Términos.

AccountManager - administra la cuenta en el dispositivo. Solicitar tokens de autenticación que deberías usar AccountManager.

AbstractAccountAuthenticator - componente para trabajar con tipos de cuentas. Contiene toda la lógica para trabajar con la cuenta(autorización, derechos de acceso, etc.) Uno AbstractAccountAuthenticator puede ser utilizado por diferentes aplicaciones (como la cuenta de Google para Gmail, Calendario, Unidad, etc.)

AccountAuthenticatorActivity - base Activity, para autorizar/crear cuenta. AccountManager llama a esta cuenta si es necesario identificar la cuenta(Token no existe o expirado)

Cómo funciona? Mira la imagen de abajo:

diagrama de gestión de cuentas android

Pasos.

1). Crear Authenticator;

Necesitas extender AbstractAccountAuthenticator y anular 7 métodos:

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

Ejemplo:

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;
    }
}

Explicación:

Por lo tanto, necesita ver solo 2 métodos: addAccount, getAuthToken.

En addAccount he añadido algunos parámetros de configuración, que serán utilizados por mi Activity para el Inicio de sesión del usuario. El punto principal aquí es intent.putExtra(Config.ARG_ACCOUNT_TYPE, accountType); - debe especificar el tipo de cuenta aquí. Otras manipulaciones no son necesarias.

En getAuthToken - Lea los comentarios por favor . He copiado y pegado este método desde UdinicAuthenticator.java

Además, necesitarás los siguientes permisos en tu 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" />

Resumen de los métodos addAccount y getAuthToken

Trate de obtener token, si el token existe devolver el resultado, de lo contrario verá Activity para la autorización

2). Crear Activity para el Inicio de sesión del usuario;

Ver AutenticadoraCtividad

Breve explicación: Crear formulario con ID de usuario y Contraseña. Uso del ID de usuario y contraseña data obtiene el token de autenticación del servidor y luego ejecuta el siguiente paso:

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

3). Crear un Service para comunicarse con la cuenta.

Véase UdinicAuthenticatorService

No olvides añadir esta línea en AndroidManifest.xml a Service:

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

Y también en res/xml añadir archivo 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"/>

Eso es todo. Puedes usar tu AccountAuthenticator.

Para materiales de origen gracias a

 89
Author: Alexander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-26 14:51:19

El AccountManager es bueno por las siguientes razones:

  • Primero es almacenar varios nombres de cuenta con diferentes niveles de acceso a las funciones de la aplicación bajo un solo tipo de cuenta. Por ejemplo, en una aplicación de transmisión de video, una puede tener dos nombres de cuenta: una con acceso de demostración a un número limitado de videos y la otra con acceso de mes completo a todos los videos. Esta no es la razón principal para usar Accounts, sin embargo, ya que puede administrar fácilmente en su aplicación sin la necesidad de esto de aspecto elegante Accounts cosa... .
  • La otra ventaja de usar Accounts es deshacerse de la autorización tradicional con nombre de usuario y contraseña cada vez que el usuario solicita una función autorizada, porque la autenticación se realiza en segundo plano y al usuario se le pide su contraseña solo en ciertas condiciones, que llegaré a ella más adelante.
  • El uso de la función Accounts en Android también elimina la necesidad de definir el propio tipo de cuenta. Probablemente te hayas encontrado las aplicaciones que utilizan cuentas de Google para la autorización, lo que ahorra la molestia de hacer una nueva cuenta y recordar sus credenciales para el usuario.
  • Accounts se puede agregar de forma independiente a través de Configuración → Cuentas
  • La autorización de usuario multiplataforma se puede administrar fácilmente utilizando Accounts. Por ejemplo, el cliente puede acceder a material protegido al mismo tiempo en su dispositivo Android y PC sin la necesidad de inicios de sesión recurrentes.
  • Desde el punto de vista de la seguridad, utilizando el mismo la contraseña en cada solicitud al servidor permite posibles escuchas en conexiones no seguras. El cifrado de contraseñas no es suficiente aquí para evitar el robo de contraseñas.
  • Finalmente, una razón importante para usar la función Accounts en android es separar las dos partes involucradas en cualquier negocio dependiente de Accounts, el llamado autenticador y propietario de recursos, sin comprometer las credenciales del cliente (usuario). Los términos pueden parecer bastante vagos, pero no te rindas hasta que leas el siguiente párrafo ...

Permítanme explayarme sobre este último con un ejemplo de una aplicación de transmisión de video. La compañía A es titular de un negocio de transmisión de video en contrato con la Compañía B para proporcionar a sus ciertos miembros servicios de transmisión premium. La compañía B emplea un método de nombre de usuario y contraseña para reconocer a su usuario. Para que la Compañía A reconozca a los miembros premium de B, una forma sería obtener la lista de ellos de B y utilizar un mecanismo similar de coincidencia de nombre de usuario/contraseña. Este de manera, el autenticador y el propietario del recurso son los mismos (Empresa A). Aparte de la obligación del usuario de recordar una segunda contraseña, es muy probable que establezca la misma contraseña que el perfil de su Empresa B para usar los servicios de A. Esto obviamente no es favorable.

Para disipar las deficiencias anteriores, se introdujo OAuth. Como un estándar abierto para la autorización, en el ejemplo anterior, OAuth exige que la autorización sea realizada por la Empresa B (autenticador) por emitir algún token llamado Token de acceso para los usuarios elegibles (terceros) y luego proporcionar a la empresa A (propietario del recurso) el token. Así que ningún token significa ninguna elegibilidad.

He elaborado más sobre esto y más en AccountManager en mi sitio web en aquí

 6
Author: Ali Nem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-12 06:23:17

En la configuración de Android tienes cuentas para tu tipo de cuenta y desde allí puedes agregar una cuenta. AccountManager también es un lugar central para almacenar credenciales para que solo inicie sesión una vez por cada vendedor. Si descarga otra aplicación de Google o accede a una aplicación varias veces, solo ingresa las credenciales una vez

 0
Author: Pomagranite,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-24 02:51:01