Я не могу получить токены на android-приложение с сервера django

Я пытаюсь понять, почему я не могу получить токены доступа в моем android-приложении с сервера django. Структура приложения для android кажется мне нормальной. Тем не менее проблема сохраняется.

Я протестировал ответ сервера с помощью postman, и он выглядит нормально (я получаю оба токена, доступ и обновление), но в моем приложении для android это не работает. Когда я вызываю функцию входа в систему из приложения, ответ сервера равен 200, но у меня нет токенов, сохраненных в xml-файле. Я делюсь с вами некоторыми фрагментами кода в надежде, что кто-нибудь здесь сможет мне помочь. Заранее благодарю любого!

ФУНКЦИЯ ВХОДА В СИСТЕМУ

suspend fun loginUser(userService: UserService, email: String, password: String, context: Context, navController: NavController) {
    try {
        val response = userService.loginUser(UserLoginRequest(email, password)).await()
        if (response.isSuccessful) {
            val tokenResponse = response.body()!!
            TokenManager.saveTokens(tokenResponse.accessToken, tokenResponse.refreshToken)
            withContext(Dispatchers.Main) {
                navController.navigate(Screen.FeedScreen.route)
            }
        } else {
            withContext(Dispatchers.Main) {
                Toast.makeText(context, "Login failed: ${response.message()}", Toast.LENGTH_LONG).show()
            }
        }
    } catch (e: Exception) {
        withContext(Dispatchers.Main) {
            Toast.makeText(context, "An error occurred: ${e.localizedMessage}", Toast.LENGTH_LONG).show()
        }
    }
}

МЕНЕДЖЕР ТОКЕНОВ

package com.example.events.util


import android.content.SharedPreferences
import android.util.Log
import com.example.events.network.NetworkModule
import com.example.events.network.RefreshRequestBody
import com.example.events.network.RefreshTokenResponse
import com.example.events.network.TokenRefreshService
import com.google.gson.Gson

object TokenManager {
    private lateinit var preferences: SharedPreferences

    // Initialise with SharedPreferences
    fun init(preferences: SharedPreferences) {
        this.preferences = preferences
    }

    val accessToken: String?
        get() = preferences.getString("access", null)

    fun isTokenExpired(): Boolean {
        val expiry = preferences.getLong("expiry", 0)
        return expiry < System.currentTimeMillis()
    }

    fun refreshToken(): String? {
        val refreshTokenValue = preferences.getString("refresh", null) ?: return null
        val refreshRequestBody = RefreshRequestBody(refreshTokenValue)

        try {
            val call = NetworkModule.retrofit.create(TokenRefreshService::class.java)
                .refreshToken(refreshRequestBody)
            val response = call.execute()

            if (response.isSuccessful) {
                val refreshTokenResponse =
                    Gson().fromJson(response.body()?.string(), RefreshTokenResponse::class.java)
                refreshTokenResponse?.let {
                    with(preferences.edit()) {
                        putString("access", it.access)
                        putString("refresh", it.refresh)
                        putLong(
                            "expiry",
                            System.currentTimeMillis() + 1000 * 60 * 5
                        ) // Adjust based on actual token expiry from backend
                        apply()
                    }
                    return it.access
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        // No need for finally block to close the ResponseBody when using Retrofit
        return null
    }


    fun saveTokens(accessToken: String, refreshToken: String) {
        if (accessToken.isNotEmpty() && refreshToken.isNotEmpty()) {
            preferences.edit().apply {
                putString("access", accessToken)
                putString("refresh", refreshToken)
                apply()
            }
        } else {
            Log.e("TokenManager", "Attempted to save null or empty tokens.")
        }
    }

}

СЕРВИСНАЯ ФУНКЦИЯ ПОЛЬЗОВАТЕЛЯ

@Headers("Content-Type: application/json")
    @POST("/users/login/")
    fun loginUser(@Body data: UserLoginRequest): Deferred<Response<TokenResponse>>

СЕТЕВОЙ МОДУЛЬ

package com.example.events.network

import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.net.CookieManager
import java.net.CookiePolicy

object NetworkModule {
    private const val BASE_URL = "http://192.168.0.100:8000/"

    val retrofit: Retrofit by lazy {
        /*val cookieManager = CookieManager().apply {
            setCookiePolicy(CookiePolicy.ACCEPT_ALL)
        }*/

        val client = OkHttpClient.Builder()
            .addInterceptor(AuthInterceptor()) // Add the AuthInterceptor
//            .cookieJar(JavaNetCookieJar(cookieManager)) // Add Cookie Manager
            .build()

        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(CoroutineCallAdapterFactory())
            .build()
    }
}

AUTH INTERCEPTOR

package com.example.events.network

import com.example.events.util.TokenManager
import okhttp3.Interceptor
import okhttp3.Response

class AuthInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val accessToken = TokenManager.accessToken
        val requestBuilder = chain.request().newBuilder()

        // Add the Authorization header
        accessToken?.let {
            requestBuilder.addHeader("Authorization", "Bearer $it")
        }

        // Proceed with the original request
        val originalResponse = chain.proceed(requestBuilder.build())

        // Check if the token is expired after receiving the response
        if (TokenManager.isTokenExpired()) {
            synchronized(this) {
                // Close the original response to avoid IllegalStateException
                originalResponse.close()

                val newAccessToken = TokenManager.refreshToken()
                newAccessToken?.let {
                    // Add the new access token to the Authorization header
                    requestBuilder.addHeader("Authorization", "Bearer $it")
                }

                // Retry the request with the new access token
                return chain.proceed(requestBuilder.build())
            }
        }

        // Return the original response if the token was not expired
        return originalResponse
    }
}

ОТВЕТ НА ТОКЕН

package com.example.events.model

data class TokenResponse(
    val accessToken: String,
    val refreshToken: String
)

ЗАПРОС НА ВХОД ПОЛЬЗОВАТЕЛЯ

package com.example.events.model.user

data class UserLoginRequest(
    val email: String, // or username, in future
    val password: String
)
Вернуться на верх