vue許可權控制
目錄
vue許可權控制
在SPA(單頁面應用)中,前端需要根據使用者的許可權來控制使用者選單以及路由表,vue-router
提供了幾個路由生命週期鉤子,叫做路由守衛
,我們可以利用路由守衛在路由以及路由元資訊進行許可權控制,同時搭配vuex將會更美味,文末有完整示例地址
登入許可權
登入驗證是最常見的一種路由許可權驗證,使用vuex
+ 路由守衛可以實現比較清晰流暢的鑑權流,能輕鬆應對頁面重新整理、清除快取等場景。
路由元資訊
vue-router
在構建路由時提供了元資訊meta
配置介面,我們可以在元資訊中新增路由對應的許可權,然後在路由守衛中檢查相關許可權,控制其路由跳轉。
// router.js
// 路由表元資訊
[
{
path: '',
redirect: '/home'
},
{
path: '/home',
meta: {
title: 'Home',
icon: 'home'
}
},
{
path: '/userCenter',
meta: {
title: '個人中心',
requireAuth: true // 在需要登入的路由的meta中新增響應的許可權標識
}
}
]
// 在守衛中訪問元資訊
function gaurd (to, from, next) {
// to.matched.some(record => record.meta.requireAuth)
// 可在此處
}
vuex
一般的,使用者登入後會在本地持久化儲存使用者的認證資訊,本文以JWT
的token
auth
,方便用語許可權控制。
// store.js
{
state: {
token: window.localStorage.getItem('token'),
auth: false,
userInfo: {}
},
mutations: {
setToken (state, token) {
state.token = token
window.localStorage.setItem('token', token)
},
clearToken (state) {
state.token = ''
window.localStorage.setItem('token', '')
},
setUserInfo (state, userInfo) {
state.userInfo = userInfo
state.auth = true // 獲取到使用者資訊的同時將auth標記為true,當然也可以直接判斷userInfo
}
},
actions: {
async getUserInfo (ctx, token) {
return fetchUserInfo(token).then(response => {
if (response.code === 200) {
ctx.commit('setUserInfo', response.data)
}
return response
})
},
async login (ctx, account) {
return login(account).then(response => {
if (response.code === 200) {
ctx.commit('setUserInfo', response.data.userInfo)
ctx.commit('setToken', response.data.token)
}
})
}
}
}
路由守衛
寫好路由表和vuex之後,給所有路由設定一個全域性守衛,在進入路由之前進行許可權檢查,並導航到對應的路由。
// router.js
router.beforeEach(async (to, from, next) => {
if (to.matched.some(record => record.meta.requireAuth)) { // 檢查是否需要登入許可權
if (!store.state.auth) { // 檢查是否已登入
if (store.state.token) { // 未登入,但是有token,獲取使用者資訊
try {
const data = await store.dispatch('getUserInfo', store.state.token)
if (data.code === 200) {
next()
} else {
window.alert('請登入')
store.commit('clearToken')
next({ name: 'Login' })
}
} catch (err) {
window.alert('請登入')
store.commit('clearToken')
next({ name: 'Login' })
}
} else {
window.alert('請登入')
next({ name: 'Login' })
}
} else {
next()
}
} else {
next()
}
})
後記
上述的方法是基於jwt
認證方式,本地不持久化使用者資訊,只儲存token
,當用戶重新整理或者重新開啟網頁時,進入需要登入的頁面都會嘗試去請求使用者資訊,該操作在整個訪問過程中只進行一次,直到重新整理或者重新開啟,對於應用後期的開發維護和擴充套件支援都很好。
動態載入選單和路由
有時候為了安全,我們需要根據使用者許可權或者是使用者屬性去動態的新增選單和路由表,可以實現對使用者的功能進行定製。vue-router
提供了addRoutes()
方法,可以動態註冊路由,需要注意的是,動態新增路由是在路由表中push
路由,由於路由是按順序匹配的,因此需要將諸如404
頁面這樣的路由放在動態新增的最後。
路由元資訊
// store.js
// 將需要動態註冊的路由提取到vuex中
const dynamicRoutes = [
{
path: '/manage',
name: 'Manage',
meta: {
requireAuth: true
},
component: () => import('./views/Manage')
},
{
path: '/userCenter',
name: 'UserCenter',
meta: {
requireAuth: true
},
component: () => import('./views/UserCenter')
}
]
vuex
在vuex
中新增userRoutes
陣列用於儲存使用者的定製選單。在setUserInfo
中根據後端返回的選單生成使用者的路由表。
// store.js
setUserInfo (state, userInfo) {
state.userInfo = userInfo
state.auth = true // 獲取到使用者資訊的同時將auth標記為true,當然也可以直接判斷userInfo
// 生成使用者路由表
state.userRoutes = dynamicRoutes.filter(route => {
return userInfo.menus.some(menu => menu.name === route.name)
})
router.addRoutes(state.userRoutes) // 註冊路由
}
修改選單渲染
// App.vue
<div id="nav">
<router-link to="/">主頁</router-link>|
<router-link to="/login">登入</router-link>
<template v-for="(menu, index) of $store.state.userInfo.menus">
|<router-link :to="{ name: menu.name }" :key="index">{{menu.title}}</router-link>
</template>
</div>
結束語
上述為前端控制選單和路由許可權的兩種實現思路,經過本人實踐效果令人滿意,如果有更好的想啊歡迎交流,附上完整示例地址:https://github.com/YES-Lee/vue-permission-demo