Как проверить срок действия токена у перехватчиков android дооснащения? - PullRequest
0 голосов
/ 05 марта 2020

Я хотел бы самостоятельно обработать срок действия токена и отправить запрос на новые токены. У меня есть такое условие:

sp.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60

Это условие проверяет, когда мой токен истечет, и я должен отправить новый запрос от перехватчика. Я видел этот вопрос также. Я создал такой перехватчик:

class RefreshTokens(cont: Context) : Interceptor{
    val context = cont
    override fun intercept(chain: Interceptor.Chain): Response {
        var tokenIsUpToDate = false
        val sp = context.getSharedPreferences("app_data", 0)
        if (sp.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60) {
            Singleton.apiService(context).getNewToken(ReqAccessToken(context.getSharedPreferences("app_data", 0).getString("refresh_token", ""))).enqueue(object : Callback<ResNewTokens>, retrofit2.Callback<ResNewTokens> {
                override fun onResponse(call: Call<ResNewTokens>, response: retrofit2.Response<ResNewTokens>) {
                    if (response.isSuccessful) {
                        tokenIsUpToDate = true
                    }
                }

                override fun onFailure(call: Call<ResNewTokens>, t: Throwable) {

                }

            })

            return if (tokenIsUpToDate) {
                chain.proceed(chain.request())
            } else {
                chain.proceed(chain.request())
            }

        } else {
            val response = chain.proceed(chain.request())
            when (response.code) {
                401->{
                    chain.request().url
                    response.request.newBuilder()
                            .header("Authorization", "Bearer " + context.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
                            .build()
                }
                500 -> {
                    Toast.makeText(context, context.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
                }
            }
            return response
        }
    }
}

Я не представляю, как добавить условие возврата в мой код. Я знаю о Authentificator, но когда я использую его, я отправляю еще один запрос, ответ на который дает мне 401 ошибку для обновления токена. Когда я использую Authentificator, я отправляю такие запросы:

  1. Запрос со старым access_token -> 401 ошибка
  2. Запрос новых токенов -> 200 OK
  3. Запрос с новым access_token -> 200 OK

Поэтому я хотел бы удалить 1 запрос, который выдаст ошибку, и отправить запрос на новые токены. Но у меня есть проблемы:

  1. Я не знаю, как исправить перехватчик для решения этой задачи
  2. Я не знаю, как повторить запрос, который я собирался сделать как в Аутентификаторе

Может кто знает, как решить мою проблему?

Ответы [ 2 ]

3 голосов
/ 05 марта 2020

Да, это слишком просто, не принимай, это сложно, у меня тоже есть такая же проблема, но я решаю вот так

Так что, когда токен истекает, Retrofit дает код ошибки

= 401

Таким образом, вам нужно сохранить данные пользователя, используя sharedPref userEmail или userName , а также userPassword So

Когда пользователь получает сообщение или ошибку токена exipre код 401 , вам необходимо вызвать метод для входа в систему пользователя снова, чтобы показать что-либо пользователю, используя useremail и userpassword , затем генерируется токен fre sh, затем отправляется этот сгенерированный токен на сервер, и в этом случае он будет работать

Надеюсь, это поможет

0 голосов
/ 18 марта 2020

Я хотел бы поделиться своим собственным решением, которое работает хорошо, как я вижу:

class AuthToken(context: Context) : Interceptor {
    var cont = context
    override fun intercept(chain: Interceptor.Chain): Response {
        val sp = cont.getSharedPreferences("app_data", 0)
        if (sp!!.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60 && !sp.getString("refresh_token", "")!!.isBlank()) updateAccessToken(cont)

        val initialRequest = if (sp.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60 && !sp.getString("refresh_token", "")!!.isBlank()) {
            updateAccessToken(cont)
            requestBuilder(chain)
        } else {
            requestBuilder(chain)
        }


        val initialResponse = chain.proceed(initialRequest)

        return if (initialResponse.code == 401 && !sp.getString("refresh_token", "").isNullOrBlank() && sp.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60) {
            updateAccessToken(cont)
            initialResponse.close()
            val authorizedRequest = initialRequest
                    .newBuilder()
                    .addHeader("Content-type:", "application/json")
                    .addHeader("Authorization", "Bearer " + cont.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
                    .build()
            chain.proceed(authorizedRequest)
        } else {
            val errorBody = initialResponse.message
            when {

            }
            if (initialResponse.code == 500) {
                val thread = object : Thread() {
                    override fun run() {
                        Looper.prepare()
                        Toast.makeText(cont, cont.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
                        Looper.loop()
                    }
                }
                thread.start()
            }
            initialResponse
        }
    }


    private fun updateAccessToken(context: Context) {
        val sp = context.getSharedPreferences("app_data", 0)
        synchronized(this) {
            val tokensCall = accessTokenApi()
                    .getNewToken(ReqAccessToken(context.getSharedPreferences("app_data", 0).getString("refresh_token", "")!!))
                    .execute()

            if (tokensCall.isSuccessful) {
                val responseBody = tokensCall.body()
                val editor = sp.edit()

                val localTime = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH).parse(tokensCall.headers()["Date"]!!)
                Singleton.setServerTime(localTime!!.time / 1000, context)

                editor.putString("access_token", Objects.requireNonNull<ResNewTokens>(responseBody).access_token).apply()
                editor.putString("refresh_token", Objects.requireNonNull<ResNewTokens>(responseBody).refresh_token).apply()
                editor.putLong("expires_in", responseBody!!.expires_in!!).apply()
            } else {
                when (tokensCall.code()) {
                    500 -> {
                        val thread = object : Thread() {
                            override fun run() {
                                Looper.prepare()
                                Toast.makeText(cont, cont.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
                                Looper.loop()
                            }
                        }
                        thread.start()
                    }

                    401 -> {
                        Singleton.logOut(context)
                    }
                }
            }

        }
    }


    private fun requestBuilder(chain: Interceptor.Chain): Request {
        return chain.request()
                .newBuilder()
                .header("Content-type:", "application/json")
                .header("Authorization", "Bearer " + cont.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
                .build()
    }

    private fun accessTokenApi(): APIService {
        val interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY

        val dispatcher = Dispatcher()
        dispatcher.maxRequests = 1


        val client = OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .connectTimeout(100, TimeUnit.SECONDS)
                .dispatcher(dispatcher)
                .readTimeout(100, TimeUnit.SECONDS).build()


        client.dispatcher.cancelAll()

        val retrofit = Retrofit.Builder()
                .baseUrl(BuildConfig.API_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()

        return retrofit.create(APIService::class.java)
    }
}

В общем, как я вижу, я отправляю запрос на обновление токена перед отправкой запроса с просроченным access_token. Может быть, у кого-то будут какие-то предложения или улучшения для моего решения:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...