Sto lavorando a un sistema token Oauth2 per accedere alla mia API REST per la mia app per Android. Sto riscontrando qualche problema con la parte di rinfresco dei token sul lato client.Come implementare un processo di aggiornamento dei token con JWT per le app Android
Ecco il flusso: La mia app fa una richiesta (con un token di accesso nel parametro) al server grazie alcuni AsyncTask (PostCommentAsyncTask()
, AddFriendAsyncTask()
ecc ...), per cui se l'access token è valido è ok, ma se è scaduto chiamo un altro AsyncTask
(GetRefreshTokenAsyncTask()
) dal metodo onPostExecute()
del precedente AsyncTask
per ottenere un nuovo accesso. Ecco la parte difficile per me. Quando ricevo il nuovo token di accesso, voglio rieseguire la richiesta AsyncTask iniziale sul server. Non riesco a capire come farlo correttamente.
example1:
richiesta PostCommentAsyncTask()
-> (acessToken scaduto) ->GetRefreshTokenAsyncTask()
-> Richiesta PostCommentAsyncTask()
-> (buona token) -> Ok
EDIT:
Alla fine ho scelto di utilizzare la libreria Volley
(non è più necessario utilizzare Asynctask). Come io uso JSON Web Token
Posso controllare la data di scadenza che è codificata nel payload del token.
Ecco il metodo isAccessTokenExpired()
per verificare se il token di accesso non sia scaduto prima di fare una richiesta al server:
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;
}
}
e qui è il metodo refreshJsonWebToken()
per ottenere un nuovo paio di token di accesso/gettone Refresh dal mio server 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);
}
E finnally il metodo getPost()
dove io uso i metodi precedenti:
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);
}
È possibile utilizzare il metodo 'get() del secondo' AsyncTask' in 'metodo doInBackground()' del tuo primo 'AsyncTask'. Il metodo 'get()' di AsyncTask' è un metodo di blocco che restituisce un risultato - è completamente inutile usarlo sul thread principale/dell'interfaccia utente ma se lo si chiama dal primo 'AsyncTask''s' doInBackground() ' metodo (che gira sul proprio thread), quindi è possibile continuare semplicemente con l'attività originale quando viene restituito il secondo metodo 'get()' di AsyncTask'. Solo un'idea – Squonk
@ Frédéric: quale libreria hai usato sul lato server per la concessione della password OAuth2? Sto usando Node come backend. – j10