Estamos utilizando Retrofit en nuestra aplicación de Android para comunicarnos con un servidor seguro OAuth2. Todo funciona muy bien, utilizamos RequestInterceptor para incluir el token de acceso con cada llamada. Sin embargo, habrá momentos en los que el token de acceso caducará y el token debe actualizarse. Cuando el token caduca, la próxima llamada regresará con un código HTTP no autorizado, por lo que es fácil de monitorear. Podríamos modificar cada llamada de Retrofit de la siguiente manera: en la devolución de llamada fallida, verifique el código de error, si es igual a No autorizado, actualice el token OAuth, luego repita la llamada de Retrofit. Sin embargo, para esto, todas las llamadas deben modificarse, lo cual no es una solución fácil de mantener y buena. ¿Hay alguna manera de hacer esto sin modificar todas las llamadas de Retrofit?
157
Respuestas:
No lo use
Interceptors
para tratar con la autenticación.Actualmente, el mejor enfoque para manejar la autenticación es utilizar la nueva
Authenticator
API, diseñada específicamente para este propósito .OkHttp solicitará automáticamente las
Authenticator
credenciales cuando una respuesta401 Not Authorised
vuelva a intentar la última solicitud fallida con ellas.Adjunte una
Authenticator
a deOkHttpClient
la misma manera que lo hace conInterceptors
Use este cliente al crear su
Retrofit
RestAdapter
fuente
TokenAuthenticator
depende de una unaservice
clase. Laservice
clase depende de unaOkHttpClient
instancia. Para crear unOkHttpClient
necesito elTokenAuthenticator
. ¿Cómo puedo romper este ciclo? ¿DosOkHttpClient
s diferentes ? Tendrán diferentes grupos de conexión ...Si está utilizando Retrofit > =
1.9.0
, podría utilizar el nuevo Interceptor de OkHttp , que se introdujo enOkHttp 2.2.0
. Desea utilizar un interceptor de aplicaciones , que le permiteretry and make multiple calls
.Su interceptor podría parecerse a este pseudocódigo:
Después de definir su
Interceptor
, creeOkHttpClient
y agregue el interceptor como un interceptor de aplicación .Y finalmente, use esto
OkHttpClient
cuando cree suRestAdapter
.Advertencia: como
Jesse Wilson
(de Square) menciona aquí , esta es una cantidad peligrosa de energía.Dicho esto, definitivamente creo que esta es la mejor manera de manejar algo como esto ahora. Si tiene alguna pregunta, no dude en hacer un comentario.
fuente
Si tiene, por ejemplo, un Retrofit
TokenService
que necesita dentro de su,Authenticator
pero solo le gustaría configurar uno para elOkHttpClient
que pueda usarTokenServiceHolder
como dependenciaTokenAuthenticator
. Tendría que mantener una referencia a él en el nivel de aplicación (singleton). Esto es fácil si está utilizando Dagger 2, de lo contrario, simplemente cree un campo de clase dentro de su aplicación.En
TokenAuthenticator.java
En
TokenServiceHolder.java
:Configuración del cliente:
Si está utilizando Dagger 2 o un marco de inyección de dependencia similar, hay algunos ejemplos en las respuestas a esta pregunta
fuente
TokenService
crea la clase?refreshToken()
fromservice.refreshToken().execute();
? No puedo encontrar su implementación en ningún lado.Usar
TokenAuthenticator
like @theblang answer es una forma correcta de manejarrefresh_token
.Aquí está mi implemento (he usado Kotlin, Dagger, RX pero puede usar esta idea para implementar en su caso)
TokenAuthenticator
Para evitar el ciclo de dependencia como el comentario de @Brais Gabin, creo 2 interfaces como
y
AccessTokenWrapper
claseAccessToken
claseMi interceptor
Finalmente, agregue
Interceptor
yAuthenticator
a suOKHttpClient
cuando cree el servicio PotoAuthApiManifestación
https://github.com/PhanVanLinh/AndroidMVPKotlin
Nota
Autenticador de flujogetImage()
devuelve el código de error 401authenticate
método en el interiorTokenAuthenticator
será despedidononeAuthAPI.refreshToken(...)
llamadononeAuthAPI.refreshToken(...)
respuesta -> nuevo token se agregará al encabezadogetImage()
llamará AUTO con un nuevo encabezado (HttpLogging
NO registrará esta llamada) (intercept
dentroAuthInterceptor
NO LLAMARÁ )Si
getImage()
todavía se produjo el error 401,authenticate
método en el interiorTokenAuthenticator
voluntad disparó una y otra vez , entonces va a tirar de error sobre el método llamado muchas veces (java.net.ProtocolException: Too many follow-up requests
). Puede prevenirlo por conteo de respuesta . Ejemplo, sireturn null
enauthenticate
los 3 tiempos de reintento,getImage()
será terminar yreturn response 401
Si la
getImage()
respuesta es exitosa => obtendremos el resultado normalmente (como usted llamagetImage()
sin error)Espero que ayude
fuente
Sé que este es un hilo viejo, pero por si alguien tropezó con él.
Estaba enfrentando el mismo problema, pero quería crear solo un OkHttpClient porque no creo que necesite otro solo para el TokenAuthenticator en sí, estaba usando Dagger2, así que terminé brindando la clase de servicio cuando Lazy inyectó en el TokenAuthenticator, puedes leer más sobre la inyección diferida en Dagger 2 aquí , pero es básicamente como decirle a Dagger que NO vaya y cree el servicio que TokenAuthenticator necesita de inmediato.
Puede consultar este hilo SO para obtener un código de muestra: ¿Cómo resolver una dependencia circular mientras todavía usa Dagger2?
fuente
Puede intentar crear una clase base para todos sus cargadores en la que pueda detectar una excepción particular y luego actuar según lo necesite. Haga que todos sus cargadores diferentes se extiendan desde la clase base para difundir el comportamiento.
fuente
Después de una larga investigación, personalicé el cliente Apache para manejar Refreshing AccessToken For Retrofit en el que envía token de acceso como parámetro.
Inicie su adaptador con cookie Persistent Client
Cookie Cliente persistente que mantiene cookies para todas las solicitudes y verifica con cada respuesta de solicitud, si es acceso no autorizado ERROR_CODE = 401, actualiza el token de acceso y recupera la solicitud, de lo contrario solo procesa la solicitud.
fuente
El uso de un Interceptor (inyectar el token) y un Autenticador (operaciones de actualización) hacen el trabajo pero:
También tuve un problema de doble llamada: la primera llamada siempre devolvió un 401 : el token no se inyectó en la primera llamada (interceptor) y se llamó al autenticador: se realizaron dos solicitudes.
La solución fue solo para volver a efectuar la solicitud a la compilación en el Interceptor:
ANTES DE:
DESPUÉS:
EN UN BLOQUE:
Espero eso ayude.
Editar: no encontré una manera de evitar la primera llamada para siempre devolver 401 usando solo el autenticador y sin interceptor
fuente
Para cualquiera que quisiera resolver llamadas simultáneas / paralelas al actualizar el token. Aquí hay una solución
fuente