Vuejs Laravel Passport - что мне делать, если срок действия токена истек? - PullRequest
0 голосов
/ 31 мая 2019

Я использую Vuejs SPA с Laravel API в качестве бэкэнда. Я успешно получил токен личного доступа и сохранил его в состоянии localStorage и Vuex, как показано ниже.

token: localStorage.getItem('token') || '',
expiresAt: localStorage.getItem('expiresAt') || '',

Я использую токен доступа каждый раз, когда отправляю запрос axios в laravel api. Все работает хорошо. Тем не менее, изначально токен был установлен на 1 год, поэтому, когда я развивался, мне было все равно, что токен истек, и сегодня внезапно я подумал, что произойдет, если токен истечет. Поэтому я установил срок действия токена на 10 секунд в laravel AuthServiceProvier.php.

Passport::personalAccessTokensExpireIn(Carbon::now()->addSecond(10));

и затем я вошел в систему и через 10 секунд все запросы перестали работать, потому что токен истек и получил 401 несанкционированную ошибку.

В таком случае, как я могу узнать, истек ли токен? Я хотел бы перенаправить пользователя на страницу входа, если токен истек, когда пользователь использует веб-сайт.

Ответы [ 2 ]

0 голосов
/ 31 мая 2019

Будьте максимально удобны для пользователя. Вместо ожидания истечения срока действия токена, получения ответа об ошибке 401 и последующего перенаправления, установите проверку проверки токена на смонтированном хуке вашего основного экземпляра SPA и попросите его выполнить ajax-вызов, например, /validatePersonalToken на сервере, затем сделайте что-то подобное в своих маршрутах или контроллере.

Route::get('/validatePersonalToken', function () {
      return ['message' => 'is valid'];
})->middleware('auth:api');

Это должно вернуть "error": "Unauthenticated", если токен недействителен. Таким образом, пользователю будет предложено аутентифицировать , прежде чем продолжить , чтобы использовать приложение и отправлять данные, а затем потенциально потерять работу (например, отправку формы), что не очень удобно для пользователя.

Вы могли бы сделать это на компоненте за компонентом, а не на главном экземпляре, используя Vue Mixin. Это будет работать лучше для очень недолговечных токенов, которые могут истечь во время использования приложения. Поставьте проверку в хук mounted() миксина, а затем используйте этот миксин в любом компоненте, который выполняет вызовы API, чтобы проверка выполнялась при монтировании этого компонента. https://vuejs.org/v2/guide/mixins.html

0 голосов
/ 31 мая 2019

Это то, что я делаю. Axios выдаст ошибку, если код ответа 4xx или 5xx, а затем я добавлю if, чтобы проверить, если статус ответа 401, а затем перенаправлю на страницу входа.

export default {
    methods: {
        loadData () {
            axios
                .request({
                    method: 'get',
                    url: 'https://mysite/api/route',
                })
                .then(response => {
                    // assign response.data to a variable
                })
                .catch(error => {
                    if (error.response.status === 401) {
                        this.$router.replace({name: 'login'})
                    }
                })
        }
    }
}

Но если вы сделаете это так, вам придется скопировать вставку catch для всех вызовов axios внутри ваших программ. Я сделал так, чтобы поместить приведенный выше код в javascript-файлы api.js, импортировать класс в main.js и назначить его в Vue.prototype. $ Api

import api from './api'
Object.defineProperty(Vue.prototype, '$api', { value: api })

Так что в моем компоненте я просто называю такие аксиосы.

this.$api.GET(url, params)
    .then(response => {
        // do something
    })

Ошибка обрабатывается на api.js. Это мой полный api.js

import Vue from 'vue'
import axios from 'axios'
import router from '@/router'

let config = {
  baseURL : process.env.VUE_APP_BASE_API,
  timeout : 30000,
  headers : {
    Accept         : 'application/json',
    'Content-Type' : 'application/json',
  },
}

const GET = (url, params) => REQUEST({ method: 'get', url, params })
const POST = (url, data) => REQUEST({ method: 'post', url, data })
const PUT = (url, data) => REQUEST({ method: 'put', url, data })
const PATCH = (url, data) => REQUEST({ method: 'patch', url, data })
const DELETE = url => REQUEST({ method: 'delete', url })

const REQUEST = conf => {
  conf = { ...conf, ...config }
  conf = setAccessTokenHeader(conf)

  return new Promise((resolve, reject) => {
    axios
      .request(conf)
      .then(response => {
        resolve(response.data)
      })
      .catch(error => {
        outputError(error)
        reject(error)
      })
  })
}

function setAccessTokenHeader (config) {
  const access_token = Vue.cookie.get('access_token')
  if (access_token) {
    config.headers.Authorization = 'Bearer ' + access_token
  }

  return config
}

/* https://github.com/axios/axios#handling-errors */
function outputError (error) {
  if (error.response) {
    /**
     * The request was made and the server responded with a
     * status code that falls out of the range of 2xx
     */
    if (error.response.status === 401) {
      router.replace({ name: 'login' })
      return
    }
    else {
      /* other response status such as 403, 404, 422, etc */
    }
  }
  else if (error.request) {
    /**
     * The request was made but no response was received
     * `error.request` is an instance of XMLHttpRequest in the browser
     * and an instance of http.ClientRequest in node.js
     */
  }
  else {
    /* Something happened in setting up the request that triggered an Error */
  }
}

export default {
  GET,
  POST,
  DELETE,
  PUT,
  PATCH,
  REQUEST,
}
...