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 agreguesynchronized
palabra clave a tuTokenAuthenticator
sauthenticate
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 usarSchedulers.trampoline()
oblockingGet()
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 enTokenAuthenticator
.
Esto es lo que estamos tratando de lograr:
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);