#android #authorization #retrofit2 #interceptor #okhttp3
#Android #авторизация #retrofit2 #перехватчик #okhttp
Вопрос:
Я хочу использовать authorization
в Retrofit2
. Я выбрал interceptor
способ, потому что почти все методы требуют authorization
, за исключением одного, где я получаю токен для дальнейшего использования с другими методами.
Мой вопрос: как я могу этого добиться?
Я храню свой токен доступа в SharedPreferences
. Моей первой идеей было: «Я могу извлечь его в своем RetrofitClient
классе и в зависимости от того, равен ли токен нулю или у него есть значение, создать подходящий Retrofit
экземпляр» (с добавлением к нему .client()
или без него.).
К сожалению, это не так просто, потому что Context
необходимо получить настройки.
Я не знаю, как передать его в RetrofitClient
класс или как добраться до него внутри.
Вот мой RetrofitClient
класс:
public class RetrofitClient {
public static final String BASE_URL = "http://localhost";
public static Retrofit retrofit = null;
private RetrofitClient() {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
//.client(getRequestHeader())
.build();
}
/*OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Authorization", "Bearer" )
}
})*/
public static synchronized Retrofit getInstance() {
if (retrofit == null) {
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
}
return retrofit;
}
public Api getApi() {
return retrofit.create(Api.class);
}
}
Мой getRequestHeader()
предыдущий метод, в котором я устанавливал тайм-аут.
Я хочу создать экземпляр, подобный этому:
private RetrofitClient() {
tokenService.token = null;
tokenService.readToken(ApplicationContext.getInstance());
if (tokenService.token == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
} else {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client) //I have interceptor here with access token
.build();
}
}
И затем:
RetrofitClient.getInstance().create(Api.class).getToken()
//получение токена
RetrofitClient.getInstance().create(Api.class).someMethod()
// когда я получаю токен
Хороший ли это подход?
Ответ №1:
Вы можете использовать контекст приложения, который доступен, пока ваше приложение работает. Получите его из своего класса app:
public class MyApp extends Application {
private static MyApp instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
//other code
}
public static MyApp getInstance() {
return instance;
}
А затем просто используйте MyApp.getInstance()
, чтобы получить контекст там, где вам нужно. С помощью этого подхода вы можете достичь того, о чем думали раньше, и получить SharedPreferences в RetrofitClient
классе.
Не забудьте добавить свой класс приложения в manifest.
ОБНОВЛЕНИЕ: Вы создаете свой экземпляр retrofit только один раз, поэтому, если вы создадите его, когда у вас будет токен — вы всегда будете использовать его, пока приложение работает. Я думаю, хорошей практикой является проверка наличия токена в вашем перехватчике. Что-то вроде этого:
new Interceptor() {
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
if (tokenService.token == null) {
return chain.proceed(request);
} else {
return chain.proceed(request.newBuilder().addHeader("Authorization", "Bearer" tokenService.token).build());
}
}
}
Кроме того, я не знаю, как работает ваш токенсервис. Но имейте в виду, что лучше всего всегда проверять токен в общих настройках, если вы очищаете его там при выходе из системы. Потому что ваш токенсервис может сохранить строку токена, даже если она очищена в общих настройках.
Комментарии:
1. И последний простой вопрос. Если я вызову,
RetrofitClient.getInstance().create(Api.class).getToken()
а затемRetrofitClient.getInstance().create(Api.class).someMethod()
для чего требуется токен, будет ли он вести себя хорошо? Пожалуйста, проверьте модификацию конструктора в моей правке.2. @SkypeDogg Я обновил свой ответ, надеюсь, теперь это понятно
3. Класс
TokenService
имеет одно строковое поле для токена и три метода:saveToken()
,readToken()
иclearToken()
но каждый раз, когда я включаю приложение, я запрашиваю токен с PIN-кодом, но я использую следующие методы, только если токен возвращается с кодом200
, в противном случае он сообщает о неправильном PIN-коде. Каждый раз, когда возвращается новый токен, он переопределяет старый PIN, поэтому, я надеюсь, ошибок быть не должно, даже безclearToken()
метода4. @SkypeDogg отлично, надеюсь, я тебе немного помог
Ответ №2:
Просто добавьте SharedPreferences в качестве параметра конструктора в RetrofitClient или другом, в зависимости от ситуации
Ответ №3:
Вы можете сделать следующим образом:
Сначала создайте класс предпочтений с помощью экземпляра singleton
Настройки
public class Preferences {
public static Preferences INSTANCE;
private final String PREFERENCE_FILE = "my_preferences";
public final String PREF_TOKEN = "pref_user_token";
private SharedPreferences mPrefs;
private SharedPreferences.Editor mEdit;
private Preferences() {
Application app = MyApplicationClass.getInstance();
mPrefs = app.getSharedPreferences(PREFERENCE_FILE, Context.MODE_PRIVATE);
mEdit = mPrefs.edit();
}
// Returns singleton instance
public static Preferences getInstance() {
if (INSTANCE == null)
INSTANCE = new Preferences();
return INSTANCE;
}
public String getToken() {
return Preferences.getInstance().mPrefs.getString(PREF_TOKEN, "");
}
public void saveToken(String value) {
mEdit.putString(PREF_TOKEN, value);
mEdit.apply();
}
}
Затем измените свой класс RetrofitClient, как показано ниже:
RetrofitClient
public class RetrofitClient {
public static final String BASE_URL = "http://localhost";
public static Retrofit retrofit = null;
private RetrofitClient() {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(mClient)
.build();
}
OkHttpClient mClient = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Authorization", "Bearer" Preferences.getInstance().getToken())
}
})
public static synchronized Retrofit getInstance() {
if (retrofit == null) {
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
}
return retrofit;
}
public Api getApi() {
return retrofit.create(Api.class);
}
}