2015-05-26 13 views
5

Używam Auth0, co daje mi JWT (json web token) i refreshtoken. Używam tego JWT w nagłówkach HTTP do komunikacji z moim zapleczem.Jak radzić sobie z błędem auth0 403 bez dodawania konkretnego kodu wszędzie (Retrofit/okhttp/RxAndroid)

Może się zdarzyć, że serwer poda mi 403, kiedy zdecyduje, że JWT wygasło. W tym przypadku mogę poprosić Auth0 o wystawienie mi nowego JWT, używając refreshtoken. Oznacza to, że nazywam backend Auth0, przekazuję go refreshtoken i daje mi to nowy JWT, który mogę następnie wykorzystać w moich żądaniach.

Moje pytanie brzmi: jak mogę skutecznie zapisać to zachowanie w całym moim kodzie sieciowym? Będę miał kilka punktów końcowych, z którymi można porozmawiać, i wszystkie one mogą zwrócić 403.

Myślę, że najpierw powinienem stworzyć przechwytujący, który dodaje ŚC dla wszystkich wniosków.

Następnie powinno być zachowanie, które wykrywa 403, cicho robi połączenie sieciowe z Auth0, pobierając nową JWT. Następnie oryginalna prośba powinna zostać wypróbowana ponownie, z nowym JWT w nagłówkach.

Tak więc wolałbym, aby ta obsługa 403 była gdzieś niewidoczna dla mojego innego kodu i zdecydowanie nie musiałem jej przepisywać wszędzie.

Wszelkie wskazówki na temat tego, jak to osiągnąć, zostaną docenione.

-

Żeby było jasne, ja w zasadzie szuka wskazówek, w jaki sposób to osiągnąć stosując RxAndroid obserwabli. Kiedy pewien obserwator znajdzie 403, powinien "wstrzyknąć" nowe połączenie sieciowe.

Odpowiedz

11

I rozwiązać ten problem pisząc Interceptor dla OkHttp. Sprawdza kod statusu połączenia sieciowego. Jeśli jest to 403, wywołaj serwery Auth0 i zażądaj nowego id_token. Następnie użyj tego tokena w nowej wersji pierwotnego żądania.

Aby przetestować, pisałem trochę serwer WWW, który sprawdza TestHeader dla nie lub uda i zwraca 403, czy to nie.

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

Potem dołączyć ten Interceptor do OkHttpClient które podłączam do adaptera modernizacyjny:

// 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

Zamiast odświeżania tokenów tylko po otrzymaniu odpowiedzi 403, można sprawdzić czas wygaśnięcia lokalnie i odświeżyć odpowiednio, sprawdzając żądanie tokena o numerze exp. Na przykład this example uses the same approach in Angular. To nie jest specyficzny dla Androida, ale idea jest ta sama:

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; 
    } 
} 
Powiązane problemy