Saltar al contenido

Android Retrofit2 Refresh Oauth 2 Token

Este equipo de trabajo ha estado por horas buscando para dar respuesta a tu pregunta, te brindamos la solución por esto nuestro objetivo es serte de gran apoyo.

Solución:

Descargo de responsabilidad : En realidad estoy usando Dagger +RxJava + Retrofit pero solo quería dar una respuesta para demostrar la lógica a los futuros visitantes.

Importante : Si realiza solicitudes desde varios lugares, su token se actualizará varias veces dentro TokenAuthenticator clase. Por ejemplo, cuando su aplicación y su servicio realizan solicitudes al mismo tiempo. Para superar este problema, solo agregue synchronized palabra clave a tu TokenAuthenticators authenticate método.

Realice solicitudes sincrónicas al actualizar su token en el interior Authenticator porque debe bloquear ese hilo hasta que finalice su solicitud, de lo contrario, sus solicitudes se ejecutarán dos veces con tokens antiguos y nuevos. Puedes usar Schedulers.trampoline() o blockingGet() al actualizar su token para bloquear ese hilo.

Tambien adentro authenticate Puede verificar si el token ya está actualizado comparando el token de solicitud con el token almacenado para evitar actualizaciones innecesarias.

Y por favor no considere usar TokenInterceptor porque es un caso extremo y no para todos, solo concéntrese en TokenAuthenticator.

Esto es lo que estamos tratando de lograr:

ingrese la descripción de la imagen aquí

En primer lugar, la actualización del token es un proceso crítico para la mayoría de las aplicaciones. Muchas aplicaciones funcionan así: si el token de actualización falla, cierre la sesión del usuario actual y advierta al usuario que vuelva a iniciar sesión. (Tal vez vuelva a intentar actualizar el token de par antes de cerrar la sesión del usuario)

De todas formas te lo explicaré paso a paso:

Paso 1: Consulte el patrón singleton, crearemos una clase que se encargará de devolver nuestra instancia de actualización. Ya que es static si no hay una instancia disponible, solo crea una instancia solo una vez y cuando la llamas siempre devuelve esto static ejemplo. Esta es también la definición básica del patrón de diseño Singleton.

public class RetrofitClient 

private static Retrofit retrofit = null;

private RetrofitClient() 
    // private constructor to prevent access
    // only way to access: Retrofit client = RetrofitClient.getInstance();


public static Retrofit getInstance() 
    if (retrofit == null) 
        // our authenticator
        TokenAuthenticator tokenAuthenticator = new TokenAuthenticator();

        // !! This interceptor is not required for everyone !!
        // Main purpose of this interceptor is to reduce server calls

        // Our token needs to be refreshed after 10 hours
        // We open our app after 50 hours and try to make a request.
        // Of course token is expired and it will return 401.
        // So this interceptor checks time and refreshes token beforehand.
        // If this fails and I get 401 then my TokenAuthenticator does his job.
        // if my TokenAuthenticator fails too, basically I just logout the user.
        TokenInterceptor tokenInterceptor = new TokenInterceptor();

        OkHttpClient okClient = new OkHttpClient.Builder()
                .authenticator(tokenAuthenticator)
                .addInterceptor(tokenInterceptor)
                .build();

        retrofit = new Retrofit.Builder()
                .baseUrl(base_api_url)
                .client(okClient)
                .build();
    
    return retrofit;
  

Paso 2: En mi TokenAuthenticator’s authenticate método:

@Override
public Request authenticate(Route route, Response response) throws IOException 

    boolean refreshResult = refreshToken();
    if (refreshResult) 
    // refresh token is successful, we saved new token to storage.
    // Get your token from storage and set header
    String newaccesstoken = "your new access token";

    // make current request with new access token
    return response.request().newBuilder()
            .header("Authorization", newaccesstoken)
            .build();

     else 
        // Refresh token failed, you can logout user or retry couple of times
        // Returning null is critical here, it will stop the current request
        // If you do not return null, the request gets called again and again
        // You will end up in a loop calling refresh again and again
        return null;
    

Y refreshToken método, este es solo un ejemplo que puede crear el suyo:

public boolean refreshToken() 
    // you can use RxJava with Retrofit and add blockingGet
    // it is up to you how to refresh your token
    RefreshTokenResult result = retrofit.refreshToken();
    int responseCode = result.getResponseCode();

    if(responseCode == 200) 
        // save new token to sharedpreferences, storage etc.
        return true;
     else 
        //cannot refresh
        return false;
     

Paso 3: Para los que quieren ver TokenInterceptor lógica:

public class TokenInterceptor implements Interceptor 
SharedPreferences prefs;
SharedPreferences.Editor prefsEdit;

@Override
public Response intercept(Chain chain) throws IOException 

    Request newRequest = chain.request();

    // get expire time from shared preferences
    long expireTime = prefs.getLong("expiretime",0);
    Calendar c = Calendar.getInstance();
    Date nowDate = c.getTime();
    c.setTimeInMillis(expireTime);
    Date expireDate = c.getTime();

    int result = nowDate.compareTo(expireDate);
    // when comparing dates -1 means date passed so we need to refresh token
    if(result == -1) 
        //refresh token here , and get new access token
        TokenResponse tokenResponse = refreshToken();

        // Save refreshed token's expire time :
        integer expiresIn = tokenResponse.getExpiresIn();
        Calendar c = Calendar.getInstance();
        c.add(Calendar.SECOND,expiresIn);
        prefsEdit.putLong("expiretime",c.getTimeInMillis());

        String newaccessToken = "new access token";
        newRequest=chain.request().newBuilder()
                .header("Authorization", newaccessToken)
                .build();
    
    return chain.proceed(newRequest);
  

Estoy realizando solicitudes en el servicio de solicitud y en segundo plano. Ambos usan la misma instancia de actualización y puedo administrar fácilmente las solicitudes. Consulte esta respuesta e intente crear su propio cliente. Si aún tiene problemas, simplemente comente a continuación o envíe un correo electrónico. Intentaré ayudar. Espero que esto ayude.

En tus ApiClient.java clase :

OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new AuthorizationInterceptor(context))
                .build();

Agregar TokenManager.java class en su paquete de modernización

package co.abc.retrofit;

/**
 * Created by ravindrashekhawat on 17/03/17.
 */

public interface TokenManager 
    String getToken();
    boolean hasToken();
    void clearToken();
    String refreshToken();

Agregue la clase Intercepter en su paquete con el nombre AuthorizationInterceptor.java

package co.smsmagic.retrofit;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;

import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;

import co.abc.models.RefreshTokenResponseModel;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
import retrofit2.http.Header;

import static co.abc.utils.abcConstants.ACCESS_TOKEN;
import static co.abc.utils.abcConstants.BASE_URL;
import static co.abc.utils.abcConstants.GCM_TOKEN;
import static co.abc.utils.abcConstants.JWT_TOKEN_PREFIX;
import static co.abc.utils.abcConstants.REFRESH_TOKEN;

/**
 * Created by ravindrashekhawat on 21/03/17.
 */

public class AuthorizationInterceptor implements Interceptor 
    private static Retrofit retrofit = null;
    private static String deviceToken;
    private static String accessToken;
    private static String refreshToken;
    private static TokenManager tokenManager;
    private static Context mContext;

    public AuthorizationInterceptor(Context context) 
        this.mContext = context;
    

    @Override
    public Response intercept(Chain chain) throws IOException  response.code() == 422)
            unauthorized=true;
        

        if (unauthorized) 
            tokenManager.clearToken();
            tokenManager.refreshToken();
            accessToken = sharedPreferences.getString(ACCESS_TOKEN, "");
            if(accessToken!=null)
                modifiedRequest = request.newBuilder()
                        .addHeader("Authorization", JWT_TOKEN_PREFIX + tokenManager.getToken())
                        .build();
                return chain.proceed(modifiedRequest);
            
        
        return response;
    

Nota : Este es el código de trabajo para el token de actualización que te he proporcionado, mantén la calma solo para cambiar alguna constante, excepto que funcionará perfectamente. Solo trata de entender la lógica.

En la parte inferior hay lógica para volver a llamar a la misma solicitud.

 if(accessToken!=null)
                modifiedRequest = request.newBuilder()
                        .addHeader("Authorization", JWT_TOKEN_PREFIX + tokenManager.getToken())
                        .build();
                return chain.proceed(modifiedRequest);
  

Te mostramos reseñas y valoraciones

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *