我想在网络请求中更新访问 token 。但是使用 Dagger 和 Retrofit 有一些困难。
😢对不起,我的英文不好,所以给你一个例子可能会很清楚。从头开始,我的想法是这样的:
provide an access token saved in shared preference
@Provides
@ForOauth
Preference<String> provideAccessToken(RxSharedPreferences prefs) {
return prefs.getString(PrefsUtils.KEY_ACCESS_TOKEN);
}
use access token to create an interceptor and added into okhttp client
@Provides
@Singleton
@Named("Cached")
public OkHttpClient provideOkHttpClientWithCache(Application application, @ForOauth OauthInterceptor oauthInterceptor) {
...
builder.addInterceptor(oauthInterceptor);
...
}
and I provide the
OauthInterceptor
instance by its constructor
@Inject
public OauthInterceptor(@ForOauth Preference<String> accessToken) {
this.accessToken = accessToken;
Timber.tag("OauthInterceptor");
}
但是由于 okhttp 客户端是单例的,所以当 prefs 中的访问 token 更新时它不会改变。我认为可能可行的另一种方法是使用自定义范围,如
@ForOauth
什么的,但它只是一个粗略的草图......顺便说一句,我还有一个这样的想法:
get the access token from prefs in the
intercept()
method , so every time I can have a request header which contains the latest access token.
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
if (accessToken.isSet()) {
// Preference<String> accessToken
builder.header("Authorization", ACCESS_TYPE + accessToken.get());
} else {
builder.header("Authorization", "Bearer xxxxxx");
}
return chain.proceed(builder.build());
}
但是我还没有真正尝试过这个想法,我认为它是不对的😂
我想知道我是否必须每次都创建一个新的 okhttp 客户端实例,或者我可以更新访问 token 然后 okhttp 客户端单例可以刷新它的拦截器......
所以你能给我一些建议,或者一个简单的工作例子。
提前谢谢😊
最佳答案
嗯,我已经这样做了很多次,并且从未注意到访问 token 刷新没有沿着链向下传递到 OkHttp 的任何问题。这是我在应用程序中使用的典型设置:
@Provides @Singleton
SharedPreferences providePreferences(Context ctx) {
return new SharedPreferences(ctx);
}
@Provides @Singleton
HttpLoggingInterceptor provideLoggingInterceptor(){
return new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);
}
@Provides @Singleton
OkHttpClient provideClient(HttpLoggingInterceptor interceptor, SharedPreferences prefs){
return new OkHttpClient.Builder()
.addNetworkInterceptor(chain -> {
// Add Auth Header
String token = prefs.accessToken().get();
if(token == null) token = "";
Request request = chain.request().newBuilder().addHeader("Authorization", token).build();
return chain.proceed(request);
})
.addInterceptor(interceptor)
.build();
}
@Provides @Singleton
Retrofit provideRetrofit(@ApiUrl String url, OkHttpClient client){
return new Retrofit.Builder()
.baseUrl(url)
.client(client)
.addConverterFactory(LoganSquareConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
SharedPreferences
只是一个类,我抽象了一些 RxSharedPreferences
逻辑成。也可以@Inject
它也可以在应用程序中的任何需要它的地方使用,这很好。这是该类的一个简单版本,只是为了好玩:public class SharedPreferences {
// Constants and variables
private static final String PREFERENCE_FILENAME = BuildConfig.APPLICATION_ID + ".prefs";
private static final String PREF_ACCESS_TOKEN= "pref_access_token";
private RxSharedPreferences mRxSharedPrefs;
// Constructor
public SharedPreferences(Context context) {
mRxSharedPrefs = RxSharedPreferences.create(context.getSharedPreferences(PREFERENCE_FILENAME, Context.MODE_PRIVATE));
}
// Helper methods
public Preference<String> accessToken() { return mRxSharedPrefs.getString(PREF_ACCESS_TOKEN, ""); }
public void logout() { accessToken().delete(); }
}
关于android - 访问 token 更新 Dagger 和 Retrofit 时更新请求 header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39136081/