我想在网络请求中更新访问令牌。但是使用Dagger和Retrofit有一些困难。
抱歉,我的英语不好,所以给你一个例子可能很清楚。从头开始,我的想法是这样的:
提供以共享首选项
保存的访问令牌
@Provides
@ForOauth
Preference<String> provideAccessToken(RxSharedPreferences prefs) {
return prefs.getString(PrefsUtils.KEY_ACCESS_TOKEN);
}
使用访问令牌创建拦截器并添加到okhttp客户端
@Provides
@Singleton
@Named("Cached")
public OkHttpClient provideOkHttpClientWithCache(Application application, @ForOauth OauthInterceptor oauthInterceptor) {
...
builder.addInterceptor(oauthInterceptor);
...
}
我通过构造函数
提供OauthInterceptor
实例
@Inject
public OauthInterceptor(@ForOauth Preference<String> accessToken) {
this.accessToken = accessToken;
Timber.tag("OauthInterceptor");
}
但是因为okhttp客户端是单例,当prefs中的访问令牌更新时它不会改变。我认为可行的另一种方法是使用@ForOauth
之类的自定义范围,但它只是一个草图......
顺便说一下,我还有另外一个想法:
在
intercept()
方法中从prefs获取访问令牌,因此每次我都有一个包含最新访问令牌的请求标头。
@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客户端实例,或者我只能更新访问令牌,然后okhttp客户端单例可以刷新其拦截器......
那么请你给我一些建议,或者一个简单的工作实例。
提前致谢
答案 0 :(得分:0)
@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(); }
}