通过vuex存储token,通过前置路由守卫完成对登录操作之后的token值验证,完成登录状态的保持
- 账号和密码正确,则需要来保持用户的登录状态而前后端分离如何保存登录状态
- 保持用户的登录状态 cookie/session [考虑到跨域问题]
- 前后端分离保持用户登录状态的方案 token
- token是后端返回给前端一个加密后的字符串,需要在本地进行保存
- token存储在vuex中,对于vuex中需要持久化的内容可以存储在本地浏览器中
一、除过登录路由,在其他路由跳转之时判断token值是否存在。
全局前置路由守卫
每次路由跳转之前触发:
一般可以通过元信息来判断,哪些路由可以不登录就可以访问,那些路由需要这个token才能访问,当然也可以用地址
router.beforeEach((to,from,next)=>{
console.log("to",to.meta);
console.log("from",from);
if(to.path != '/login'){
next({
path: '/admin/staff',
replace: true
})
}else{
next()
}
})
通过在路由中添加met元信息来判断访问那些路由需要登录之后(有token值)才能验证访问,
router.beforeEach((to,from,next)=>{
console.log("to",to.meta);
console.log("from",from);
if(to.meta.istoken){
next({
path: '/',
replace: true
})
}else{
next()
}
})
那么如何去存储这个token值呢。
对token不了解的话可以看这篇token描述已经应用场景
首先能想到的是在这个全局的登录之后各个页面(大部分)是需要这个鉴权验证,也就是对当前用户的判定,也就是生成一个唯一的token值,在后面的每次http访问都带上:
- 那我们这能想到的是除了登陆请求,在请求拦截器中对所有的请求添加 token 请求字段
import axios from 'axios'
const instance = axios.create()
//把get暂时存在sessionStoring中
//给请求头添加token。
instance.interceptors.request.use(config => {
config.url != '/api/login' ? (config.headers.token = store.getters.token) : null
return config
})
这里通过express框架,搭建一个简易服务器,针对一路由请求对token是否存在的进行判断,
let allows = [
'/api/login',
'/api/upfile'
]
module.exports = (req, res, next) => {
let token = req.headers.token || ''
if (!allows.includes(req.path)) {
if (token == '') {
res.send({
code: 1000,
msg: 'token无效',
data: null
})
return;
}
// 如果token存在,进行解密,得到明文
// 明文中一般会有账号和对应的用户id信息,用此信息在数据表中去查询,如果存在,则返回数据,不存在返回,没有授权
next()
}
next()
}
*******************************************
const checkToken = require('./middleware')
app.use(checkToken);
考虑到:那这个token其实需要在全局的的组中都需要用到,就把它放在vuex中,
并想到数据持久化。
在给vuex传入的同时,进行本地存储;
import {
doLoginApi
} from '@/api/userApi'
import Store from '@/utils/store'
import {
hasToken
} from '@/utils/token'
const sessionStore = new Store()
export default {
state: {
token: '',
nickname: ''
},
mutations: {
// 写入vuex的同时,进行本地存储,为了持久化
setUserLoginInfo(state, payload) {
state.token = payload.token
state.nickname = payload.nickname;
!hasToken() && setStorage(payload)
},
userLogout(state, payload) {
state.token = ''
state.nickname = ''
sessionStore.remove('token')
sessionStore.remove('nickname')
window.location.href = '/login'
}
},
actions: {
// 进行网络请求的调用,验证账号和密码是否正确
async fetchUserLogin({
commit
}, payload) {
let ret = await doLoginApi(payload)
// 通知vuex中的state来修改对应的token数据
commit('setUserLoginInfo', ret.data)
return ret.code
}
}
}
function setStorage({
token,
nickname
}) {
sessionStore.set('token', token)
sessionStore.set('nickname', nickname)
}
针对本地存储封装成一个类导出:
class Store {
// attrname 它是 sessionStorage 还是 localStorage
// constructor(attrName = 'sessionStorage') {
// session / local
constructor(attrName = 'session') {
this.attrName = attrName + 'Storage'
}
set(key, value) {
if (typeof value == 'object') {
value = JSON.stringify(value)
}
// sessionStorage.setItem(key, value)
window[this.attrName].setItem(key, value)
}
get(key, defaultValue = '') {
let value = window[this.attrName].getItem(key)
value = value ? value : defaultValue
value = /[\[\{]/.test(value) ? JSON.parse(value) : value
return value
}
remove(key) {
window[this.attrName].removeItem(key)
}
}
// export default new Store()
export default Store