Как реализовать автоматическое обновление на стороне клиента (vue.js)? - PullRequest
0 голосов
/ 18 апреля 2019

Примечание. Я разделил свой клиент (Vue.js) и сервер (DjangoRest). Я использую JWT для проверки каждого запроса от клиента к серверу. Поток- Клиент отправляет учетные данные пользователя на сервер. Сервер отправляет обратно токен обновления и доступа, если учетные данные верны. Клиент хранит токен доступа и обновления. Я установил срок действия маркера обновления на 1 неделю, доступ к 30 минутам. Далее я хочу убедиться, что токен доступа автоматически обновляется за 15 минут до его истечения. Для этого сохраненный токен обновления на стороне клиента отправляется на сервер, затем сервер выдает новый токен доступа и токен обновления и отправляет его обратно клиенту. Как мне реализовать это в магазине Vuex? Я полный новичок в веб-разработке и vue.js. Было бы здорово, если бы кто-то мог предоставить какой-то код или объяснить подробно.

Я уже реализовал loginUser, пользователя logout, registerUser в магазине, и они работают нормально. Но я застрял с логикой автоматического обновления. Я предполагаю, что клиент должен повторно проверить оставшееся время истечения токена доступа. Когда осталось около 15 минут, мы должны инициализировать функцию автообновления. Пожалуйста, помогите мне с этой логикой.

Вот мой магазин Vueex:

import Vue from 'vue'
import Vuex from 'vuex'
import axiosBase from './api/axios-base'
Vue.use(Vuex)

export default new Vuex.Store({
  state: {
     accessToken: '' || null,
     refreshToken: '' || null
  },
  getters: {
    loggedIn (state) {
      return state.accessToken != null
    }
  },
  mutations: {
    loginUser (state) {
      state.accessToken = localStorage.getItem('access_token')
      state.refreshToken = localStorage.getItem('refresh_token')
    },
    destroyToken (state) {
      state.accessToken = null
      state.refreshToken = null
    }
  },
  actions: {
    registerUser (context, data) {
      return new Promise((resolve, reject) => {
        this.axios.post('/register', {
          name: data.name,
          email: data.email,
          username: data.username,
          password: data.password,
          confirm: data.confirm
        })
          .then(response => {
            resolve(response)
          })
          .catch(error => {
            reject(error)
          })
      })
    },
    // fetch data from api whenever required.
    backendAPI (context, data) {

    },
    logoutUser (context) {
      if (context.getters.loggedIn) {
        return new Promise((resolve, reject) => {
          axiosBase.post('/api/token/logout/')
            .then(response => {
              localStorage.removeItem('access_token')
              localStorage.removeItem('refresh_token')
              context.commit('destroyToken')
            })
            .catch(error => {
              context.commit('destroyToken')
              resolve()
            })
        })
      }
    },
    autoRefresh (context, credentials) {

    },
    loginUser (context, credentials) {
      return new Promise((resolve, reject) => {
        axiosBase.post('/api/token/', {
          username: credentials.username,
          password: credentials.password
        })
          .then(response => {
            localStorage.setItem('access_token', response.data.access)
            localStorage.setItem('refresh_token', response.data.refresh)
            context.commit('loginUser')
            resolve(response)
          })
          .catch(error => {
            console.log(error)
            reject(error)
          })
      })
    }
  }
})

Заранее спасибо.

1 Ответ

1 голос
/ 18 апреля 2019

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

Одна вещь, которую я стараюсь иметь в виду при работе с такими механизмами, - это всегда избегать опроса, когда это возможно . Вот решение, основанное на этом принципе дизайна.

токены JWT действительны в течение очень определенного периода времени. Время, оставшееся до истечения срока, легко доступно как часть токена доступа. Вы можете использовать библиотеку, такую ​​как jwt-decode , чтобы декодировать токен доступа и извлечь время истечения. После истечения срока действия у вас есть несколько доступных вариантов:

  • Проверяйте токен каждый раз перед отправкой запроса, чтобы узнать, нужно ли его обновлять
  • Используйте setTimeout, чтобы периодически обновлять его за X секунд до истечения срока его действия

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

export default new Vuex.Store({
  ...
  actions: {
    refreshTokens (context, credentials) {
      // Do whatever you need to do to exchange refresh token for access token
      ...
      // Finally, call autoRefresh to set up the new timeout
      dispatch('autoRefresh', credentials)
    },
    autoRefresh (context, credentials) {
      const { state, commit, dispatch } = context
      const { accessToken } = state
      const { exp } = jwt_decode(accessToken)
      const now = Date.now() / 1000 // exp is represented in seconds since epoch
      let timeUntilRefresh = exp - now
      timeUntilRefresh -= (15 * 60) // Refresh 15 minutes before it expires
      const refreshTask = setTimeout(() => dispatch('refreshTokens', credentials), timeUntilRefresh)
      commit('refreshTask', refreshTask) // In case you want to cancel this task on logout
    }
  }
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...