我正在使用Auth0,它给了我一个JWT(json web令牌)和一个refreshtoken.我在http标头中使用此JWT与我的后端进行通信.
当它确定JWT已经过期时,服务器可能会给我一个403.在这种情况下,我可以让Auth0使用refreshtoken向我发出一个新的JWT.这意味着我调用Auth0后端,将其传递给refreshtoken,它给了我一个新的JWT,然后我可以在我的请求中使用它.
我的问题是,如何在我的所有网络代码中有效地编写此行为?我将有几个端点可以交谈,他们都可以返回403.
然后应该有检测403的行为,静静地对Auth0进行网络调用,检索新的JWT.然后应该再次尝试原始请求,并在其标题中添加新的JWT.
所以我更喜欢将403处理到我的其他代码看不到的地方,并且绝对不必在任何地方重写它.
任何关于如何实现这一点的指示将不胜感激.
–
要清楚,我基本上是在寻找如何使用RxAndroid Observables实现这一目标的指针.当某个Observable找到403时,它应该“注入”一个新的网络呼叫.
解决方法
我通过为OkHttp编写一个Interceptor来解决这个问题.它检查网络呼叫的状态代码.如果是403,请调用Auth0服务器并请求新的id_token.然后在原始请求的新版本中使用此令牌.
为了测试,我编写了一个小的Web服务器来检查TestHeader是否失败或成功,如果失败则返回403.
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; } } }
然后我将这个Interceptor附加到一个OkHttpClient,我将其插入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(); } } )