访问令牌更新Dagger和Retrofit时更新请求标头

时间:2016-08-25 03:07:13

标签: android retrofit dagger okhttp3

我想在网络请求中更新访问令牌。但是使用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客户端单例可以刷新其拦截器......

那么请你给我一些建议,或者一个简单的工作实例。

提前致谢

1 个答案:

答案 0 :(得分:0)

嗯,我已经多次这样做了,从来没有注意到访问令牌刷新的任何问题都没有从链接到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(); }
}