Usar token de renovación si el token de autenticación expiró en el autenticador de cuenta
Tengo una aplicación que utiliza AccountManager para almacenar las cuentas de los usuarios. Los usuarios inician sesión y se registran a través de mi API REST utilizando OAuth2.0 password-username credentials flow.
Los tokens de acceso que reciben los usuarios caducan en 2 horas y necesitan ser actualizados hasta que expiren de nuevo, y así sucesivamente.
- ¿De todos modos para autenticar a un usuario que usa Google Apps en una aplicación de Android?
- Utilizar la autenticación de inicio de sesión de cuenta de Google para aplicaciones en Android
- Android Facebook SDK SSO "la página solicitada no se puede mostrar"
- Autenticación de cliente SSL con certificado en Android
- Inicia sesión con Facebook en mi sitio web Django a través de la aplicación para Android
Necesito implementar esta funcionalidad de actualización en mi autenticador.
Tengo un modelo llamado AccessToken
que tiene los campos siguientes:
String accessToken, String tokenType, Long expiresIn, String refreshToken, String scope, Long createdAt
.
Así que actualmente, en mi método getAuthToken
en la clase AccountAuthenticator
, recibo este objeto AccessToken
y uso su campo accessToken
como un Auth Token
para mi Account Manager.
Lo que necesito es guardar de alguna manera el token de actualización y el token de autenticación con mi administrador de cuentas y cuando la aplicación intenta acceder a la API y recibe la respuesta de error: {"error": "access token expired"}
para actualizar el token de acceso actual Utilizando la cadena AccessToken
objeto AccessToken
recibido anteriormente. Sin embargo, no estoy seguro de cómo debo hacerlo.
Mi método getAuthToken
en la clase de autenticador se ve actualmente así:
@Override public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String authTokenType, Bundle options) throws NetworkErrorException { 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; } final AccountManager manager = AccountManager.get(context.getApplicationContext()); String authToken = manager.peekAuthToken(account, authTokenType); Log.d("Discounty", TAG + " > peekAuthToken returned - " + authToken); if (TextUtils.isEmpty(authToken)) { final String password = manager.getPassword(account); if (password != null) { try { authToken = discountyService.getAccessToken(DiscountyService.ACCESS_GRANT_TYPE, account.name, password).toBlocking().first().getAccessToken(); // ======= // Here the above discountyService.getAccessToken(...) call returns // AccessToken object on which I call the .getAccessToken() // getter which returns a string. // ======= } catch (Exception e) { e.printStackTrace(); } } } 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; } final Intent intent = new Intent(context, 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); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; }
Y la clase AccountGeneral
sólo contiene algunas constantes:
public class AccountGeneral { public static final String ACCOUNT_TYPE = "com.discounty"; public static final String ACCOUNT_NAME = "Discounty"; public static final String AUTHTOKEN_TYPE_READ_ONLY = "Read only"; public static final String AUTHTOKE_TYPE_READ_ONLY_LABEL = "Read only access to a Discounty account"; public static final String AUTHTOKEN_TYPE_FULL_ACCESS = "Full access"; public static final String AUTHTOKEN_TYPE_FULL_ACCESS_LABEL = "Full access to a Discounty account"; }
La aplicación también utilizará SyncAdapter
e interactuará con la API con bastante frecuencia para sincronizar los datos desde y hacia el servidor, y estas llamadas a la API también necesitarán usar tokens de acceso como parámetros en las solicitudes, así que realmente necesito implementar esta actualización Funcionalidad y hacerlo automático.
¿Alguien sabe cómo implementarlo correctamente?
PS: Estaré usando una base de datos local para almacenar todos mis datos y también podría almacenar los objetos token. Esto parece un hack fácil, aunque inseguro. Tal vez debería almacenar sólo un token de actualización a la vez como un registro de db y actualizarlo como la aplicación recibe el nuevo token?
PPS: Soy libre de cambiar la forma en que funciona la API de todos modos, así que si hay sugerencias sobre cómo mejorar la aplicación para móviles, mejorando la API, también serán muy apreciados.
- ¿Existe una forma oficial de autenticar Google Data API en Android mediante cuentas AccountManager?
- Generar un certificado de cliente en un dispositivo Android
- Compruebe el inicio de sesión en todas las actividades
- Google oauth2 funciona con un código de tiempo generado desde Android pero no funciona para el código generado desde JS SDK
- La autenticación de Dropbox deja abierto el navegador
- Android: autenticación de Google
- AccountManager no permite agregar una nueva cuenta en la aplicación (el uid del llamador es diferente al uid del autenticador)
- Google signin no funciona con producción apk en playstore. (Release apk en playstore)
Puede guardar el token de actualización en los datos de usuario de su cuenta cuando agregue su cuenta por primera vez usando:
Bundle userdata = new Bundle; userdata.putString("refreshToken", refreshToken); mAccountManager.addAccountExplicitly (account, password, userdata);
También puede configurar los userdata después de agregar la cuenta llamando a:
mAccountManager.setUserData(account, "refreshToken", refreshToken);
Cuando acceda a token expirado, puede recuperar su token de actualización llamando a:
String refreshToken = mAccountManager.getUserData(account, "refreshToken");
Utilice refreshToken para recuperar un nuevo token de acceso.
- Tema no aplicado con la biblioteca appcompat en algunos dispositivos Android 4.X
- ¿Cómo terminar la aplicación de NDK (actividad nativa) de android mediante programación?