匕首+改造。在运行时添加身份验证标头

2022-09-01 06:33:57

我想知道是否有一种方法可以让Dagger知道它应该在新数据可用时重新创建一个对象。

我所说的实例是用于改造的请求标头。在某些时候(当用户登录时),我得到一个令牌,我需要将其添加到改造的标头中以发出经过身份验证的请求。问题是,我留下了相同的未经身份验证的改造版本。这是我的注入代码:

@Provides
    @Singleton
    OkHttpClient provideOkHttpClient(Cache cache) {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .cache(cache).build();
         client
                .newBuilder()
                .addInterceptor(
                    chain -> {
                        Request original = chain.request();
                        Request.Builder requestBuilder = original.newBuilder()
                                .addHeader("Accept", "Application/JSON");
                        Request request = requestBuilder.build();
                        return chain.proceed(request);
                    }).build();
        return client;
    }

  @Provides
    @Singleton
    Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) { 
        Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxErrorHandlingCallAdapterFactory.create())
                .baseUrl(mBaseUrl)
                .client(okHttpClient)
                .build();
        return retrofit;
}

@Provides
    @Singleton
    public NetworkService providesNetworkService(Retrofit retrofit) {
        return retrofit.create(NetworkService.class);
    }

关于如何使它工作的任何想法?


答案 1

我个人创建了一个为我做到这一点的方法,一旦我有了所需的令牌,我就会更新它。它看起来像这样:okhttp3.Interceptor

@Singleton
public class MyServiceInterceptor implements Interceptor {
  private String sessionToken;

  @Inject public MyServiceInterceptor() {
  }

  public void setSessionToken(String sessionToken) {
    this.sessionToken = sessionToken;
  }

  @Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();

    Request.Builder requestBuilder = request.newBuilder();

    if (request.header(NO_AUTH_HEADER_KEY) == null) {
      // needs credentials
      if (sessionToken == null) {
        throw new RuntimeException("Session token should be defined for auth apis");
      } else {
        requestBuilder.addHeader("Cookie", sessionToken);
      }
    }

    return chain.proceed(requestBuilder.build());
  }
}

在相应的匕首组件中,我公开了这个拦截器,以便我可以在需要时设置。sessionToken

这是杰克谈论过的一些事情,他的演讲使改造为你工作


答案 2

请考虑使用@oldergod中提到的方法,因为它是“官方”和更好的方法,而不建议使用下面提到的方法,它们可能被视为解决方法。


您有几种选择。

  1. 获得令牌后,您必须立即清空提供实例的组件,创建一个新组件并请求一个新实例,该实例将使用必要的实例进行实例化。RetrofitRetrofitokhttp
  2. 一个快速而糟糕的 - 将令牌保存在 中创建标头,这将应用从 中读取令牌。如果没有 - 不发送令牌标头。SharedPreferencesokHttpSharedPreferences
  3. 甚至更丑陋的解决方案 - 声明一个字段,并像步骤2一样做同样的事情。static volatile String

为什么第二种选择不好?因为在每个请求中,您将轮询磁盘并从那里获取数据。


推荐