2015-07-23 12 views
5

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); 

    } 
+0

È 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

+0

@ Frédéric: quale libreria hai usato sul lato server per la concessione della password OAuth2? Sto usando Node come backend. – j10

risposta

0

Penso che Handler sia migliore in questo caso perché Looper ha una coda di messaggi sincroni che è conveniente qui. Crei un HandlerThread e associ il tuo Handler ad esso. Quindi puoi chiamare postRunnable su di esso in base alle tue esigenze, ad es. aggiungi PostCommentRunnable, se il token è scaduto, aggiungi GetRefreshTokenRunnable e PostCommentRunnable, - verranno eseguiti in sequenza.

Se si desidera continuare con AsyncTasks, è possibile verificare se il token è scaduto prima di avviare PostCommentAsyncTask? Penso che sarà un design migliore. Se non è possibile, allora è possibile eseguire uno dopo l'altro perché lavorano sullo stesso thread in background per impostazione predefinita, ad esempio:

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. 
     } 
    } 
} 
+1

Grazie per la risposta! Posso controllare il token prima di lanciare una richiesta (grazie a JWT).Sono nuovo di Android e non ne so molto di Handler, non so come funziona Volley ma c'è un sistema di coda come gestore. Ho modificato il mio post con un po 'di lavoro spero che possa essere migliorato o aiutare chiunque! –

+0

ok, grazie per aver aggiornato il tuo post. quindi, qual è la tua domanda ora? Penso che tutto dovrebbe essere chiaro ora –