← Назад к вопросам

Как к запросу добавить токен авторизации

1.7 Middle🔥 133 комментариев
#Сетевое взаимодействие

Комментарии (3)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Добавление токенов авторизации в сетевые запросы на Android

Добавление токена авторизации к HTTP-запросам — одна из фундаментальных задач при работе с защищенными API. На практике применяется несколько подходов, каждый из которых подходит для разных сценариев и архитектур приложения.

Основные способы добавления токена авторизации

1. Использование OkHttp Interceptor (наиболее распространенный подход)

OkHttp Interceptor позволяет централизованно модифицировать все исходящие запросы. Это удобно, так как не требует изменения каждого вызова API:

class AuthInterceptor(private val tokenProvider: TokenProvider) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        
        val requestWithToken = originalRequest.newBuilder()
            .header("Authorization", "Bearer ${tokenProvider.getToken()}")
            .build()
        
        return chain.proceed(requestWithToken)
    }
}

// Инициализация OkHttpClient с интерцептором
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(AuthInterceptor(tokenProvider))
    .addInterceptor(HttpLoggingInterceptor())
    .build()

// Создание Retrofit клиента
val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

2. Динамическое добавление через Retrofit CallAdapter

Для более гибкого управления можно использовать кастомные CallAdapter, которые позволяют добавлять заголовки авторизации непосредственно перед выполнением запроса:

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class Authenticated

class AuthCallAdapterFactory : CallAdapter.Factory() {
    override fun get(
        returnType: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): CallAdapter<*, *>? {
        val nextAdapter = retrofit.nextCallAdapter(this, returnType, annotations)
        
        return object : CallAdapter<Any, Any> {
            override fun adapt(call: Call<Any>): Any {
                // Добавляем логику проверки аутентификации
                return nextAdapter.adapt(call)
            }
            
            override fun responseType(): Type = nextAdapter.responseType()
        }
    }
}

3. Руководство по безопасному хранению токенов

Никогда не храните токены в SharedPreferences или в открытом виде в памяти! Используйте следующие подходы:

  • Android Keystore System для аппаратного хранения ключей шифрования
  • EncryptedSharedPreferences из библиотеки Security Crypto
  • BiometricPrompt для дополнительной защиты
// Пример использования EncryptedSharedPreferences
val masterKey = MasterKey.Builder(context)
    .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
    .build()

val sharedPreferences = EncryptedSharedPreferences.create(
    context,
    "secure_prefs",
    masterKey,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

// Сохранение токена
sharedPreferences.edit()
    .putString("auth_token", encryptedToken)
    .apply()

4. Обработка истечения срока действия токена (Token Refresh)

Реализуйте механизм автоматического обновления токена при получении ошибки 401:

class TokenRefreshInterceptor(
    private val authRepository: AuthRepository
) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val response = chain.proceed(request)
        
        if (response.code == 401) {
            synchronized(this) {
                val newToken = authRepository.refreshToken()
                
                if (newToken != null) {
                    val newRequest = request.newBuilder()
                        .header("Authorization", "Bearer $newToken")
                        .build()
                    
                    response.close()
                    return chain.proceed(newRequest)
                }
            }
        }
        
        return response
    }
}

5. Полный пример интеграции в MVVM архитектуре

class NetworkModule {
    @Provides
    @Singleton
    fun provideOkHttpClient(
        authInterceptor: AuthInterceptor,
        tokenRefreshInterceptor: TokenRefreshInterceptor
    ): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(authInterceptor)
            .addInterceptor(tokenRefreshInterceptor)
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }
    
    @Provides
    @Singleton
    fun provideApiService(client: OkHttpClient): ApiService {
        return Retrofit.Builder()
            .baseUrl(BuildConfig.BASE_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(CoroutineCallAdapterFactory())
            .build()
            .create(ApiService::class.java)
    }
}

Рекомендации по практическому применению

  • Используйте разные токены для доступа и обновления (access/refresh tokens)
  • Реализуйте механизм безопасного логаута с инвалидацией токенов на сервере
  • Добавьте обработку сетевых ошибок и таймаутов
  • Тестируйте все сценарии: истекший токен, отсутствие сети, серверные ошибки
  • Минимизируйте время жизни токенов в соответствии с требованиями безопасности

Интерцепторы OkHttp являются наиболее предпочтительным подходом благодаря своей централизации, гибкости и поддержке сложных сценариев, таких как автоматическое обновление токенов. Важно помнить о безопасном хранении токенов и правильной обработке ошибок авторизации.