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
Interceptorspara tratar con la autenticación.Actualmente, el mejor enfoque para manejar la autenticación es utilizar la nueva
AuthenticatorAPI, diseñada específicamente para este propósito .OkHttp solicitará automáticamente las
Authenticatorcredenciales cuando una respuesta401 Not Authorisedvuelva a intentar la última solicitud fallida con ellas.Adjunte una
Authenticatora deOkHttpClientla misma manera que lo hace conInterceptorsUse este cliente al crear su
RetrofitRestAdapterfuente
TokenAuthenticatordepende de una unaserviceclase. Laserviceclase depende de unaOkHttpClientinstancia. Para crear unOkHttpClientnecesito elTokenAuthenticator. ¿Cómo puedo romper este ciclo? ¿DosOkHttpClients 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, creeOkHttpClienty agregue el interceptor como un interceptor de aplicación .Y finalmente, use esto
OkHttpClientcuando 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
TokenServiceque necesita dentro de su,Authenticatorpero solo le gustaría configurar uno para elOkHttpClientque pueda usarTokenServiceHoldercomo 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.javaEn
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
TokenServicecrea la clase?refreshToken()fromservice.refreshToken().execute();? No puedo encontrar su implementación en ningún lado.Usar
TokenAuthenticatorlike @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)
TokenAuthenticatorPara evitar el ciclo de dependencia como el comentario de @Brais Gabin, creo 2 interfaces como
y
AccessTokenWrapperclaseAccessTokenclaseMi interceptor
Finalmente, agregue
InterceptoryAuthenticatora suOKHttpClientcuando cree el servicio PotoAuthApiManifestación
https://github.com/PhanVanLinh/AndroidMVPKotlin
Nota
Autenticador de flujogetImage()devuelve el código de error 401authenticatemétodo en el interiorTokenAuthenticatorserá despedidononeAuthAPI.refreshToken(...)llamadononeAuthAPI.refreshToken(...)respuesta -> nuevo token se agregará al encabezadogetImage()llamará AUTO con un nuevo encabezado (HttpLoggingNO registrará esta llamada) (interceptdentroAuthInterceptorNO LLAMARÁ )Si
getImage()todavía se produjo el error 401,authenticatemétodo en el interiorTokenAuthenticatorvoluntad 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 nullenauthenticatelos 3 tiempos de reintento,getImage()será terminar yreturn response 401Si 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