Подтвердить что ты не робот

Кинжал + Дооснащение. Добавление заголовков auth во время выполнения

Мне интересно, есть ли способ, чтобы Кинжал знал, что он должен воссоздать объект, когда доступны новые данные.

Экземпляр, о котором я говорю, связан с заголовками запросов, которые у меня есть для доработки. В какой-то момент (когда пользователь входит в систему) я получаю токен, который мне нужно добавить в заголовки модификации, чтобы выполнить аутентифицированные запросы. Проблема в том, что я остался с той же версией, что и без проверки подлинности. Здесь мой код для инъекций:

@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);
    }

Любые идеи о том, как сделать эту работу?

4b9b3361

Ответ 1

Пожалуйста, рассмотрите подход, указанный @oldergod, поскольку он является "официальным" и гораздо лучшим способом, тогда как подходы, упомянутые ниже не, они могут рассматриваться как обходные пути.


У вас есть несколько вариантов.

  • Как только вы получите токен, вы должны исключить компонент, предоставивший экземпляр Retrofit, создать новый компонент и запросить новый экземпляр Retrofit, который будет создан с помощью okhttp экземпляр.
  • Быстрая и плохая. Сохраните токен в SharedPreferences, создайте заголовок okhttp, который будет применять чтение токена из SharedPreferences. Если их нет, не отправляйте заголовок маркера.
  • Даже более уродливое решение - объявить поле static volatile String и сделать то же самое, что и на шаге 2.

Почему второй вариант плохой? Потому что по каждому запросу вы будете проводить опрос SD-карты и получать данные оттуда.

Ответ 2

Я лично создал 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, когда мне нужно.

Вот некоторые вещи, которые Джейк говорил об этом своим разговором "Модернизация доработки" для вас.

Ответ 3

На основе решения @oldergod kotlin версии с различными классами и структурой

Сделайте экземпляр Retrofit таким

object RetrofitClientInstance {
   private var retrofit: Retrofit? = null
   private val BASE_URL = "http://yoururl"


    val retrofitInstance: Retrofit?
        get() {
            if (retrofit == null) {
                var client = OkHttpClient.Builder()
                      .addInterceptor(ServiceInterceptor())
                      //.readTimeout(45,TimeUnit.SECONDS)
                      //.writeTimeout(45,TimeUnit.SECONDS)
                        .build()

                retrofit = Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .client(client)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build()

            }
            return retrofit
      }

}

Добавьте класс ServiceInterceptor как ServiceInterceptor ниже

class ServiceInterceptor : Interceptor{

  var token : String = "";

  fun Token(token: String ) {
     this.token = token;
  }

  override fun intercept(chain: Interceptor.Chain): Response {
    var request = chain.request()

    if(request.header("No-Authentication")==null){
        //val token = getTokenFromSharedPreference();
        //or use Token Function
        if(!token.isNullOrEmpty())
        {
            val finalToken =  "Bearer "+token
            request = request.newBuilder()
                    .addHeader("Authorization",finalToken)
                    .build()
        }

    }

    return chain.proceed(request)
  }

}

Интерфейс входа и реализация класса данных

interface Login {
  @POST("Login")
  @Headers("No-Authentication: true")
  fun login(@Body value: LoginModel): Call<LoginResponseModel>



  @POST("refreshToken")
  fun refreshToken(refreshToken: String): 
      Call<APIResponse<LoginResponseModel>>
}

data class LoginModel(val Email:String,val Password:String)
data class LoginResponseModel (val token:String,val 
         refreshToken:String)

называть это в любой деятельности, как это

val service = RetrofitClientInstance.retrofitInstance?.create(Login::class.java)
val refreshToken = "yourRefreshToken"
val call = service?.refreshToken(refreshToken)
        call?.enqueue(object: Callback<LoginResponseModel>{
            override fun onFailure(call: Call<LoginResponseModel>, t: Throwable) {
                print("throw Message"+t.message)
                Toast.makeText(applicationContext,"Error reading JSON",Toast.LENGTH_LONG).show()
            }

            override fun onResponse(call: Call<LoginResponseModel>, response: Response<LoginResponseModel>) {
                val body = response?.body()
                if(body!=null){
                    //do your work
                }
            }

        })