Vuejs Laravel Passport - 如果 access token 过期了怎么办?
Vuejs Laravel Passport - what should I do if access token is expired?
我正在使用带有 Laravel API 作为后端的 Vuejs SPA。我成功地获得了个人访问令牌并存储在 localStorage 和 Vuex 状态中,如下所示。
token: localStorage.getItem('token') || '',
expiresAt: localStorage.getItem('expiresAt') || '',
我每次向 laravel api 发送 axios 请求时都使用访问令牌。每件事都运作良好。然而,最初令牌被设置为 1 年到期,所以当我开发时我并不关心令牌是否过期,今天突然我想到如果令牌过期会发生什么。所以我在 laravel AuthServiceProvier.php.
中将令牌过期时间设置为 10 秒
Passport::personalAccessTokensExpireIn(Carbon::now()->addSecond(10));
然后我登录,10 秒后,每个请求都停止工作,因为令牌已过期并收到 401 未经授权的错误。
在这种情况下,我如何知道令牌是否已过期?如果用户使用该网站时令牌已过期,我想将用户重定向到登录页面。
这就是我所做的。如果响应代码是4xx或5xx,axios会抛出错误,然后我添加一个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'})
}
})
}
}
}
但是如果你这样做,你必须复制粘贴程序中所有 axios 调用的 catch。
我这样做的方法是将上面的代码放入 javascript 文件 api.js,将 class 导入 main.js,并将其分配给 Vue.prototype.$ api
import api from './api'
Object.defineProperty(Vue.prototype, '$api', { value: api })
因此在我的组件中,我只是这样调用 axios。
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,
}
尽可能对用户友好。与其等到令牌过期,收到 401 错误响应,然后重定向,不如在主 SPA 实例的已安装挂钩上设置令牌验证检查,并让它进行 ajax 调用,例如/validatePersonalToken
在服务器上,然后在您的路由或控制器中执行类似的操作。
Route::get('/validatePersonalToken', function () {
return ['message' => 'is valid'];
})->middleware('auth:api');
如果令牌无效,这应该 return "error": "Unauthenticated"
。这样,用户将被引导到 在继续 使用应用程序和提交数据之前进行身份验证,然后可能会丢失工作(如提交表单),这对用户来说不是很友好。
您可以通过使用 Vue Mixin 在逐个组件的基础上而不是在主实例上执行此操作。这对于在使用应用程序时可能会过期的非常短暂的令牌会更好。将检查放在 mixin 的 mounted()
挂钩中,然后在进行 api 调用的任何组件中使用该 mixin,以便在安装该组件时检查为 运行。 https://vuejs.org/v2/guide/mixins.html
您可以将拦截器与 axios 一起使用。捕获 401 并清除本地存储,然后将用户重定向到适当的页面。
我正在使用带有 Laravel API 作为后端的 Vuejs SPA。我成功地获得了个人访问令牌并存储在 localStorage 和 Vuex 状态中,如下所示。
token: localStorage.getItem('token') || '',
expiresAt: localStorage.getItem('expiresAt') || '',
我每次向 laravel api 发送 axios 请求时都使用访问令牌。每件事都运作良好。然而,最初令牌被设置为 1 年到期,所以当我开发时我并不关心令牌是否过期,今天突然我想到如果令牌过期会发生什么。所以我在 laravel AuthServiceProvier.php.
中将令牌过期时间设置为 10 秒Passport::personalAccessTokensExpireIn(Carbon::now()->addSecond(10));
然后我登录,10 秒后,每个请求都停止工作,因为令牌已过期并收到 401 未经授权的错误。
在这种情况下,我如何知道令牌是否已过期?如果用户使用该网站时令牌已过期,我想将用户重定向到登录页面。
这就是我所做的。如果响应代码是4xx或5xx,axios会抛出错误,然后我添加一个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'})
}
})
}
}
}
但是如果你这样做,你必须复制粘贴程序中所有 axios 调用的 catch。 我这样做的方法是将上面的代码放入 javascript 文件 api.js,将 class 导入 main.js,并将其分配给 Vue.prototype.$ api
import api from './api'
Object.defineProperty(Vue.prototype, '$api', { value: api })
因此在我的组件中,我只是这样调用 axios。
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,
}
尽可能对用户友好。与其等到令牌过期,收到 401 错误响应,然后重定向,不如在主 SPA 实例的已安装挂钩上设置令牌验证检查,并让它进行 ajax 调用,例如/validatePersonalToken
在服务器上,然后在您的路由或控制器中执行类似的操作。
Route::get('/validatePersonalToken', function () {
return ['message' => 'is valid'];
})->middleware('auth:api');
如果令牌无效,这应该 return "error": "Unauthenticated"
。这样,用户将被引导到 在继续 使用应用程序和提交数据之前进行身份验证,然后可能会丢失工作(如提交表单),这对用户来说不是很友好。
您可以通过使用 Vue Mixin 在逐个组件的基础上而不是在主实例上执行此操作。这对于在使用应用程序时可能会过期的非常短暂的令牌会更好。将检查放在 mixin 的 mounted()
挂钩中,然后在进行 api 调用的任何组件中使用该 mixin,以便在安装该组件时检查为 运行。 https://vuejs.org/v2/guide/mixins.html
您可以将拦截器与 axios 一起使用。捕获 401 并清除本地存储,然后将用户重定向到适当的页面。