Muy buenas, soy Miguel y aquí les traigo un artículo.
Actualice su token de acceso al servidor con un interceptor OkHttp
En este artículo, aprenderá a implementar un interceptor de autenticación global. El trabajo de este interceptor es actualizar el token de acceso cuando obtiene una respuesta no autorizada.
Índice
Introducción
Actualizar su servidor a SSL no significa necesariamente que esté seguro en la naturaleza. Su servidor necesita la confirmación de que se está comunicando con el usuario sin ninguna intercepción de piratas informáticos (en su mayoría declarado como el hombre en el medio del ataque).
Nota rápida: utilice una función de fijación de certificados para evitar ataques de intermediario en la mayoría de los casos.
Aunque tenemos la fijación de certificados, es mejor tener algún tipo de verificación de usuario. Existen diferentes enfoques para verificar que se está comunicando con el usuario real, uno de los cuales es la verificación de tokens. Puede ser un token JWT estándar o su lógica personalizada.
Si vemos esta verificación de token en un nivel alto, será algo como esto: Primero, realizará una llamada de servicio regular si el código de estado de respuesta es 401, lo que significa que no está autorizado, podría ser una interceptación de un pirata informático o el token real ha caducado. En cuyo caso, tenemos que solicitar un nuevo token de acceso. Si se genera el token, entonces tenemos que reinicializar el flujo de solicitud original. De lo contrario, deberíamos cerrar la sesión del usuario, asumiendo que la conexión está comprometida.
Interceptador
Basta con la parte teórica, comencemos con lo que es un interceptor. Un interceptor es un mecanismo poderoso que puede monitorear, reescribir y reintentar llamadas de servicio. Aquí hay un interceptor simple que registra las solicitudes salientes y las respuestas entrantes.
OkHttpClient.Builder().addInterceptor(Interceptor { val request: Request = it.request() val t1 = System.nanoTime() // Logging before the request execution (String.format("Sending request %s on %s%n%s", request.url(), it.connection(), request.headers())).print() // Executing the request by invoking procced function // on the chain with the request object val response: okhttp3.Response = it.proceed(request) // Logging after the request execution val t2 = System.nanoTime() (String.format("Received response for %s in %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6, response.headers())).print() return@Interceptor response })
Interceptor de registro simple usando la biblioteca OkHttp3
AddInterceptor
es la función a través de la cual podemos agregar un interceptor al constructor de solicitudes, OkHttp builder. Luego creamos una nueva instancia de un interceptor en el que obtenemos interceptor.chain
como entrada.
De esta cadena, podemos obtener el objeto request
, que contiene información detallada sobre el cuerpo request
, los encabezados y más. Una vez que se completa la solicitud, podemos acceder a la respuesta.
Cuando la función proceed
con el objeto request
invocado en la instancia chain
, comenzará la ejecución real. El resultado de la función proceed
es la respuesta del servidor, incluida información adicional como el código de estado y otras cosas.
Interceptor de autenticación
Ahora que entendemos cómo crear un interceptor y cómo funciona, comencemos a construir el interceptor de autenticación.
El objetivo de este interceptor es invocar una actualización de la funcionalidad del token de acceso cuando la solicitud de origen emite un acceso no autorizado. Después de recuperar con éxito el token actualizado, debemos crear una instancia de la solicitud. Echar un vistazo:
OkHttpClient.Builder().addInterceptor(Interceptor { // Creating the origin request object var request: Request = it.request() // Executing the request by invoking procced function // on the chain with the request object var response: okhttp3.Response = it.proceed(request) // Verifying the whether the request is executed or not if (response.code() != 200){ if (response.code() == 401){ // This block executes when the token is expried // creating get access token service call object val call = apiService.requestNewToken(getrefreshTokenBody()) // Invoking the service call val refreshTokenResponse = call.execute() //saving the access token in preference SharedPrefManager.mTokenValue = refreshTokenResponse.token //replacing the new token in the origin request object request = request.newBuilder() .header("Authorization", refreshTokenResponse.token) .build() //reintializing the origin request response = it.proceed(request) }else{ //handle other errors here } } return@Interceptor response })
Lógica del interceptor de autenticación
Como primer paso, creamos el original objeto request
para reinicializarlo si obtenemos acceso no autorizado. En el siguiente paso, invocamos la función proceed
en la cadena con el objeto de solicitud.
En ese momento, la solicitud comienza a ejecutarse. Una vez que se complete la solicitud, obtendremos la respuesta, y lo primero que debemos hacer es verificar que la solicitud sea exitosa comparando el código de estado. Si el código de estado es 200 en la respuesta, la solicitud se ejecuta correctamente.
Si la solicitud es exitosa, tenemos que devolver la respuesta directamente. Si no es así, debemos verificar el tipo de error usando el código de estado. Si el código de estado es 401, entonces es acceso no autorizado; Asimismo, si desea manejar otros errores, debemos implementarlo en el else
bloquear.
Si la respuesta de la solicitud de origen no está autorizada, entonces debemos crear una nueva solicitud para invocar el getAccessToken
llamada de servicio. Una vez que obtenemos la respuesta primero, debemos guardar el último token de acceso en lugar de usarlo en el futuro.
Después de eso, necesitamos actualizar el último token en el objeto de solicitud original y luego reiniciar la solicitud.
Mejoramiento
Eso es todo. Ahora, su aplicación tiene un interceptor de autenticación global. Para optimizar un poco el código, podemos crear una nueva clase que amplíe el interceptor e incluya la lógica relacionada con la autenticación aquí. De esta manera, podemos aislar la funcionalidad del interceptor, por lo que el código parece más organizado. Echar un vistazo:
class ErrorHandlingInteceptor : Interceptor { override fun intercept(chain: Interceptor.Chain?): Response { // Creating the origin request object var request: Request = chain.request() // Executing the request by invoking procced function // on the chain with the request object var response: okhttp3.Response = chain.proceed(request) // Verifying the whether the request is executed or not if (response.code() != 200){ if (response.code() == 401){ // This block executes when the token is expried // creating get access token service call object val call = apiService.requestNewToken(getrefreshTokenBody()) // Invoking the service call val refreshTokenResponse = call.execute() //saving the access token in preference SharedPrefManager.mTokenValue = refreshTokenResponse.token //replacing the new token in the origin request object request = request.newBuilder() .header("Authorization", refreshTokenResponse.token) .build() //reintializing the origin request response = chain.proceed(request) }else{ //handle other errors here } } return response } }
Interceptor de manejo de errores por aislamiento de código
Para agregar el interceptor, necesitamos crear una instancia de ErrorHandlingInteceptor
, como se muestra a continuación:
val client = OkHttpClient.Builder() client.addInterceptor( ErrorHandlingInteceptor())
Gracias por leer.
Añadir comentario