jsonwebtoken - Cómo implementar un proceso de actualización de token con JWT para aplicaciones de Android
jwt desencriptar (1)
Estoy trabajando en un sistema Token Oauth2 para acceder a mi API REST para mi aplicación Android. Tengo algunos problemas con la parte del refresco del token en el lado del cliente.
Aquí está el flujo: mi aplicación hace una solicitud (con un token de acceso en el parámetro) al servidor gracias a algunas asynctask ( PostCommentAsyncTask()
, AddFriendAsyncTask()
etc ...), por lo que si el accessToken es válido, está bien, pero si ha expirado. Llamo a otra AsyncTask
( GetRefreshTokenAsyncTask()
) del método onPostExecute()
del AsyncTask
para obtener el nuevo accessToken. Aquí está la parte difícil para mí. Cuando obtengo el nuevo token de acceso, quiero volver a ejecutar la solicitud AsyncTask inicial en el servidor. No puedo entender cómo hacerlo correctamente.
Ejemplo 1 :
request PostCommentAsyncTask()
-> (acessToken caducado) -> GetRefreshTokenAsyncTask()
-> solicitud PostCommentAsyncTask()
-> (buen token) -> Ok
EDITAR:
Finalmente elegí usar la biblioteca Volley
(ya no es necesario usar Asynctask). Cuando uso JSON Web Token
, puedo verificar la fecha de caducidad que está codificada en la carga del token.
Aquí está el método isAccessTokenExpired()
para verificar si el token de acceso no ha expirado antes de realizar una solicitud al servidor:
public Boolean isAccessTokenExpired(String accessToken){
String[] accessTokenPart = accessToken.split("//.");
String header =accessTokenPart[0];
String payload =accessTokenPart[1];
String signature =accessTokenPart[2];
try {
byte[] decodedPayload = Base64.decode(payload, Base64.DEFAULT);
payload = new String(decodedPayload,"UTF-8");
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
JSONObject obj = new JSONObject(payload);
int expireDate = obj.getInt("exp");
Timestamp timestampExpireDate= new Timestamp( expireDate);
long time = System.currentTimeMillis();
Timestamp timestamp = new Timestamp(time);
return timestamp.after(timestampExpireDate);
} catch (JSONException e) {
e.printStackTrace();
return true;
}
}
Y aquí está el método refreshJsonWebToken()
para obtener un nuevo par de token Access / Refresh desde mi servidor OAUTH2:
public void refreshJsonWebToken(){
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
String refreshToken = settings.getString("refreshToken", null);
final HashMap<String, String> params = new HashMap<String, String>();
params.put("grant_type","refresh_token");
params.put("client_id","client");
params.put("refresh_token",refreshToken);
JsonObjectRequest req = new JsonObjectRequest(URL_OAUTH2, new JSONObject(params), new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
String newRefreshToken = response.getString("refresh_token");
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("accessToken", newAccessToken);
editor.putString("refreshToken", newRefreshToken);
editor.apply();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("grid", "Error: " + error.getMessage());
}
}
});
AppController.getInstance().addToRequestQueue(req);
}
Y finalmente el método getPost()
donde uso los métodos precedentes:
private void getPost(String latitude, String longitude) {
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
String accessToken = settings.getString("accessToken", null);
final HashMap<String, String> params = new HashMap<String, String>();
params.put("action", "getLocalPosts");
params.put("latitude", latitude);
params.put("longitude", longitude);
if (isAccessTokenExpired(accessToken)){
refreshJsonWebToken();
}
settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
accessToken = settings.getString("accessToken", null);
JsonObjectRequest req = new JsonObjectRequest(URL_APP+accessToken, new JSONObject(params), new Response.Listener<JSONObject>() {
//Some code ....
});
AppController.getInstance().addToRequestQueue(req);
}
Creo que Handler
es mejor en este caso porque Looper
tiene una cola de mensajes sincrónicos que es conveniente aquí. Usted crea un HandlerThread
y asocia su HandlerThread
con él. Luego puede llamar a postRunnable
dependiendo de sus necesidades, por ejemplo, agrega PostCommentRunnable
, si token ha caducado, agrega GetRefreshTokenRunnable
y PostCommentRunnable
, se ejecutarán secuencialmente.
Si aún desea AsyncTasks
, ¿puede verificar si token ha expirado antes de iniciar PostCommentAsyncTask
? Creo que será un mejor diseño. Si no puede, puede ejecutarlos uno tras otro porque trabajan en el mismo hilo de fondo por defecto, por ejemplo:
new PostCommentAsyncTask().execute();
class PostCommentAsyncTask extends AsyncTask {
//...
onPostExecute() {
if (tokenExpired) {
new GetRefreshTokenAsyncTask().execute();
new PostCommentAsyncTask().execute(); // this guy will wait till refresh token is executed.
}
}
}