设置 Axios 拦截器
我选用的 HTTP 请求套件是 axios。为了达到无痛刷新 token 的效果,我们需要对 axios 定义一个拦截器,用以接收我们刷新的 Token,代码如下:
app.js
import Vue from 'vue'
import router from './router'
import store from './store'
import iView from 'iview'
import 'iview/dist/styles/iview.css'
Vue.use(iView)
new Vue({
el: '#app',
router,
store,
created() {
// 自定义的 axios 响应拦截器
this.$axios.interceptors.response.use((response) => {
// 判断一下响应中是否有 token,如果有就直接使用此 token 替换掉本地的 token。你可以根据你的业务需求自己编写更新 token 的逻辑
var token = response.headers.authorization
if (token) {
// 如果 header 中存在 token,那么触发 refreshToken 方法,替换本地的 token
this.$store.dispatch('refreshToken', token)
}
return response
}, (error) => {
switch (error.response.status) {
// 如果响应中的 http code 为 401,那么则此用户可能 token 失效了之类的,我会触发 logout 方法,清除本地的数据并将用户重定向至登录页面
case 401:
return this.$store.dispatch('logout')
break
// 如果响应中的 http code 为 400,那么就弹出一条错误提示给用户
case 400:
return this.$Message.error(error.response.data.error)
break
}
return Promise.reject(error)
})
}
})
Vuex 内的代码如下:
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
name: null,
avatar: null,
mobile: null,
token: null,
remark: null,
auth: false,
},
mutations: {
// 用户登录成功,存储 token 并设置 header 头
logined(state, token) {
state.auth = true
state.token = token
localStorage.token = token
},
// 用户刷新 token 成功,使用新的 token 替换掉本地的token
refreshToken(state, token) {
state.token = token
localStorage.token = token
axios.defaults.headers.common['Authorization'] = state.token
},
// 登录成功后拉取用户的信息存储到本地
profile(state, data) {
state.name = data.name
state.mobile = data.mobile
state.avatar = data.avatar
state.remark = data.remark
},
// 用户登出,清除本地数据
logout(state){
state.name = null
state.mobile = null
state.avatar = null
state.remark = null
state.auth = false
state.token = null
localStorage.removeItem('token')
}
},
actions: {
// 登录成功后保存用户信息
logined({dispatch,commit}, token) {
return new Promise(function (resolve, reject) {
commit('logined', token)
axios.defaults.headers.common['Authorization'] = token
dispatch('profile').then(() => {
resolve()
}).catch(() => {
reject()
})
})
},
// 登录成功后使用 token 拉取用户的信息
profile({commit}) {
return new Promise(function (resolve, reject) {
axios.get('profile', {}).then(respond => {
if (respond.status == 200) {
commit('profile', respond.data)
resolve()
} else {
reject()
}
})
})
},
// 用户登出,清除本地数据并重定向至登录页面
logout({commit}) {
return new Promise(function (resolve, reject) {
commit('logout')
axios.post('auth/logout', {}).then(respond => {
Vue.$router.push({name:'login'})
})
})
},
// 将刷新的 token 保存至本地
refreshToken({commit},token) {
return new Promise(function (resolve, reject) {
commit('refreshToken', token)
})
},
}
})