2015-05-26 26 views
5

Sto usando Auth0, che mi dà un JWT (JSON web token) ed un refreshtoken. Io uso questo JWT nelle intestazioni http per comunicare con il mio back-end.Come gestire Auth0 403 errore senza l'aggiunta di codice specifico in tutto il mondo (Retrofit/okhttp/RxAndroid)

Potrebbe succedere che il server mi dia un 403 quando decide che il JWT è scaduto. In questo caso, posso chiedere ad Auth0 di emettermi un nuovo JWT, usando il refreshtoken. Significa che chiamo il backend Auth0, lo passo il refreshtoken e mi dà un nuovo JWT, che posso quindi usare nelle mie richieste.

La mia domanda è, come posso scrivere in modo efficiente questo comportamento in tutto il mio codice di rete? Avrò un paio di endpoint con cui parlare e tutti potrebbero restituire il 403.

Sto pensando che prima dovrei creare un intercettore che aggiunga il JWT a tutte le richieste.

Poi ci dovrebbe essere un comportamento che rileva il 403, lo fa in silenzio un networkcall a Auth0, recuperando il nuovo JWT. Quindi la richiesta originale dovrebbe essere riprovata, con il nuovo JWT nelle intestazioni.

Quindi io preferirei avere questo 403 movimentazione qualche parte invisibile al mio altro codice, e sicuramente non dover riscrivere ovunque.

Ogni punto su come ottenere questo risultato sarà apprezzato.

-

Per essere chiari, io sono fondamentalmente alla ricerca di indicazioni su come raggiungere questo obiettivo utilizzando RxAndroid osservabili. Quando un determinato Observable trova il 403, dovrebbe "iniettare" una nuova chiamata di rete.

risposta

11

Ho risolto questo problema scrivendo una Interceptor per OkHttp. Controlla il codice statico della chiamata di rete. Se si tratta di un 403, chiamare i server Auth0 e richiedere un nuovo id_token. Quindi utilizzare questo token in una nuova versione della richiesta originale.

Per provare, ho scritto un po 'di web server che controlla la TestHeader per fallire o riescono e restituisce un 403 se si tratta di falliscono.

public class AuthenticationInterceptor implements Interceptor { 

    @Override 
    public Response intercept(Chain chain) throws IOException { 
     Request originalRequest = chain.request(); 
     Request authenticationRequest = originalRequest.newBuilder() 
       .header("TestHeader", "fail") 
       .build(); 

     Response origResponse = chain.proceed(authenticationRequest); 

     // server should give us a 403, since the header contains 'fail' 
     if (origResponse.code() == 403) { 
      String refreshToken = "abcd"; // you got this from Auth0 when logging in 

      // start a new synchronous network call to Auth0 
      String newIdToken = fetchNewIdTokenFromAuth0(refreshToken); 

      // make a new request with the new id token 
      Request newAuthenticationRequest = originalRequest.newBuilder() 
        .header("TestHeader", "succeed") 
        .build(); 

      // try again 
      Response newResponse = chain.proceed(newAuthenticationRequest); 

      // hopefully we now have a status of 200 
      return newResponse; 
     } else { 
      return origResponse; 
     } 
    } 
} 

Poi mi attribuiscono questo intercettore a un OkHttpClient che inserisco nella scheda di Retrofit:

// add the interceptor to an OkHttpClient 

public static OkHttpClient getAuthenticatingHttpClient() { 
    if (sAuthenticatingHttpClient == null) { 
     sAuthenticatingHttpClient = new OkHttpClient(); 
     sAuthenticatingHttpClient.interceptors().add(new AuthenticationInterceptor()); 
    } 
    return sAuthenticatingHttpClient; 
} 

// use the OkHttpClient in a Retrofit adapter 

mTestRestAdapter = new RestAdapter.Builder() 
    .setClient(new OkClient(Network.getAuthenticatingHttpClient())) 
    .setEndpoint("http://ip_of_server:port") 
    .setLogLevel(RestAdapter.LogLevel.FULL) 
    .build(); 

// call the Retrofit method on buttonclick 

ViewObservable.clicks(testNetworkButton) 
    .map(new Func1<OnClickEvent, Object>() { 
      @Override 
      public Object call(OnClickEvent onClickEvent) { 
       return mTestRestAdapter.fetchTestResponse(); 
      } 
     } 
    ) 
2

Invece di token di aggiornamento solo dopo aver ricevuto una risposta 403, è possibile verificare la scadenza a livello locale e aggiornare di conseguenza controllando il reclamo exp del token. Ad esempio, this example uses the same approach in Angular. Non è specifico per Android, ma l'idea è la stessa:

jwtInterceptorProvider.tokenGetter = function(store, jwtHelper, auth) { 
    var idToken = store.get('token'); 
    var refreshToken = store.get('refreshToken'); 
    if (!idToken || !refreshToken) { 
    return null; 
    } 
    // If token has expired, refresh it and return the new token 
    if (jwtHelper.isTokenExpired(idToken)) { 
    return auth.refreshIdToken(refreshToken).then(function(idToken) { 
     store.set('token', idToken); 
     return idToken; 
    }); 
    // If not expired, return the token directly 
    } else { 
    return idToken; 
    } 
}