vue-element-admin?登陸及目錄權(quán)限控制的實(shí)現(xiàn)
登陸
萬事開頭難,做什么事都要有個(gè)起點(diǎn),后面才能更好的進(jìn)行下去,因此我選擇的起點(diǎn)就是最為直觀的登陸頁面 /login/index.vue
/src/views/login/index
去除那些無關(guān)的東西,比如什么 rules 校驗(yàn)啊,默認(rèn)的賬號(hào)密碼之類的東西,直接看核心登陸方法 handleLogin
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
# 請求 store 中的方法
this.$store.dispatch('LoginByUsername', this.loginForm).then(() => {
this.loading = false
this.$router.push({ path: this.redirect || '/' })
}).catch((errorMsg) => {
this.loading = false
this.$message({
type: 'error',
message: errorMsg
})
})
} else {
console.log('error submit!!')
return false
}
})
},store 主要事做一些緩存之類的處理,這里調(diào)用了 store 中的 LoginByUsername 把表單內(nèi)容傳過去,這里我就改了點(diǎn) catch 把我自己需要的錯(cuò)誤信息進(jìn)行提示,其他東西不需要改動(dòng)
/src/store/modules/user
上面登陸中請求的 LoginByUsername 正是在這
// 用戶名登錄
LoginByUsername({ commit }, userInfo) {
const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
// 請求后臺(tái)登陸
loginByUsername(username, userInfo.password).then(response => {
const data = response.data
if (response.data.errorCode !== 200) {
// 登陸失敗,回傳提示信息
reject(data.errorMsg)
}
// 設(shè)置 token,作為用戶已登陸的前端標(biāo)識(shí),存在 cookie 中
commit('SET_TOKEN', data.retData)
setToken(data.retData)
resolve()
}).catch(error => {
reject(error)
})
})
},setToken() 方法會(huì)把 token 保存到 cookie 里,很重要
下面有個(gè) GetUserInfo 方法,在你登陸的時(shí)候會(huì)去獲取你的權(quán)限數(shù)據(jù)
// 獲取用戶信息
GetUserInfo({ commit, state }) {
return new Promise((resolve, reject) => {
// 請求獲取權(quán)限
getUserInfo(state.token).then(response => {
if (response.status !== 200) { // 由于mockjs 不支持自定義狀態(tài)碼只能這樣hack
reject('error')
}
const data = response.data
if (data.retData.module && data.retData.module.length > 0) { // 驗(yàn)證返回的roles是否是一個(gè)非空數(shù)組
commit('SET_ROLES', data.retData.module)
} else {
// 當(dāng)用戶無任何權(quán)限時(shí)設(shè)置
commit('SET_ROLES', ['普通用戶'])
}
commit('SET_NAME', data.retData.username)
commit('SET_AVATAR', 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif')
commit('SET_INTRODUCTION', data.retData.username)
resolve(response)
}).catch(error => {
reject(error)
})
})
},不需要知道那個(gè) new Promise 啥的干啥用,反正我不知道,只要知道 getUserInfo 這個(gè)方法就行了,這個(gè)方法會(huì)以上面之前保存的 token 為參數(shù)去請求獲取你的用戶權(quán)限,原邏輯是沒有權(quán)限就跳登陸頁面,我這系統(tǒng)需要,沒權(quán)限也有個(gè)首頁可看,所以
SET_ROLES 參數(shù)給了個(gè)“普通用戶”,反正什么值無所謂有值,沒權(quán)限就行。
下面 commit 里的參數(shù),分別為,用戶名,頭像,介紹,保留就好,也可自定義。
PS:在每次頁面跳轉(zhuǎn)時(shí)候頁面都會(huì)走一個(gè) GetUserInfo ,以此來判斷用戶有沒有失效,因此,我的做法是直接把用戶信息包括權(quán)限保存在 redis 里取,不要每次都從庫里查
/src/utils/request.js
此文件是請求與返回?cái)r截器,我們看返回值攔截器
每次你請求從后臺(tái)接口返回時(shí),都會(huì)經(jīng)過返回值攔截器,默認(rèn)的邏輯是返回的 code 不為 20000 時(shí)候就會(huì)被攔截,這里需要我們改為自己的邏輯,很多人配置都對,點(diǎn)登錄一直 error 就是因?yàn)檫@個(gè)原因
// response interceptor
service.interceptors.response.use(
response => response,
/**
* 下面的注釋為通過在response里,自定義code來標(biāo)示請求狀態(tài)
* 當(dāng)code返回如下情況則說明權(quán)限有問題,登出并返回到登錄頁
* 如想通過 xmlhttprequest 來狀態(tài)碼標(biāo)識(shí) 邏輯可寫在下面error中
* 以下代碼均為樣例,請結(jié)合自生需求加以修改,若不需要,則可刪除
*/
// response => {
// const res = response.data
// if (res.code !== 20000) {
// Message({
// message: res.message,
// type: 'error',
// duration: 5 * 1000
// })
// // 50008:非法的token; 50012:其他客戶端登錄了; 50014:Token 過期了;
// if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// // 請自行在引入 MessageBox
// // import { Message, MessageBox } from 'element-ui'
// MessageBox.confirm('你已被登出,可以取消繼續(xù)留在該頁面,或者重新登錄', '確定登出', {
// confirmButtonText: '重新登錄',
// cancelButtonText: '取消',
// type: 'warning'
// }).then(() => {
// store.dispatch('FedLogOut').then(() => {
// location.reload() // 為了重新實(shí)例化vue-router對象 避免bug
// })
// })
// }
// return Promise.reject('error')
// } else {
// return response.data
// }
// },
error => {
console.log('err' + error) // for debug
Message({
message: '連接異常',
// message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)/src/api/login
接口的請求都會(huì)從這里去請求后臺(tái),就不多贅述,基本只需要改動(dòng)下請求路徑就ok了。
登出 logout 也是,請求保證后臺(tái)注銷,前端處理部分也是在 store/modules/user 里的 LogOut 方法,基本不需要改動(dòng)。
目錄權(quán)限
大多數(shù)系統(tǒng)都有根據(jù)用戶權(quán)限,或者說角色,展示相應(yīng)頁面的要求
/src/router/index
結(jié)合框架來實(shí)現(xiàn)目錄的控制,如果是傳統(tǒng)項(xiàng)目,一般是把目錄結(jié)構(gòu)整個(gè)存在后臺(tái)數(shù)據(jù)庫里,然后前端循環(huán)展示出來,但是這個(gè)在這里不需要這么麻煩,只需要把每個(gè)頁面對應(yīng)的權(quán)限保存起來就行了
目錄在分為兩個(gè)部分 constantRouterMap 與 asyncRouterMap
constantRouterMap:主要是通用部分,每個(gè)用戶都有的頁面
asyncRouterMap:需要進(jìn)行權(quán)限過濾的頁面
所以像首頁這種都丟在 constantRouterMap 里,而像權(quán)限管理頁面這種放在 asyncRouterMap 里
在目錄上加上 permission 標(biāo)識(shí),這個(gè)是我自定義的唯一標(biāo)識(shí),用于區(qū)分每個(gè)頁面的權(quán)限,我這里直接以頁面的路徑為值,因?yàn)槁窂娇隙ㄎㄒ?/strong>
{
path: '',
component: Layout,
alwaysShow: true,
redirect: '/xxx/xxx',
name: 'xxx',
meta: {
title: 'xxx',
icon: 'xxx'
},
children: [
{
path: '/xxx/xxx',
component: () => import('@/views/xxx/xxx'),
name: 'xxx',
meta: {
title: 'xxx',
icon: 'message',
# 權(quán)限標(biāo)識(shí),每個(gè)目錄唯一
permission: '/xxx/xxx',
noCache: false }
}
]
},然后就只需要在加載目錄時(shí)對目錄進(jìn)行判斷就可以了
/src/permission
這個(gè)文件就是整個(gè)路由邏輯在這

從這里的邏輯可以看到,登陸后,現(xiàn)在判斷了用戶權(quán)限,如果沒權(quán)限就會(huì)進(jìn)入之前說到的 GetUserInfo 方法去獲取權(quán)限,由于要對目錄進(jìn)行控制,所以在 GetUserInfo 里我們也需要獲取到目錄的權(quán)限列表,只需要獲取到有的就行了,沒有權(quán)限的目錄就不需要獲取。
在 GetUserInfo 的最后通過 resolve 方法把返回值返回這個(gè)頁面,截圖中 module 就是我獲取到的有權(quán)限的目錄列表,然后通過
GenerateRoutes 來生成要加載的目錄,接下來就是改這了
PS:不少人加我 QQ,說不明白這里什么意思,以及不知道要怎樣的目錄數(shù)據(jù),我做個(gè)簡要的說明。從這個(gè) permission 文件中我們可以看到目錄渲染一共三步:
1. GetUserInfo 中獲取到你的目錄數(shù)據(jù)(我權(quán)限數(shù)據(jù)全放這個(gè)方法里獲取了:用戶數(shù)據(jù),目錄權(quán)限,數(shù)據(jù)權(quán)限等),但這里主要的就是目錄權(quán)限
2.在上門這個(gè) permission.js 目錄渲染的邏輯中獲取 GetUserInfo 中獲取到的目錄權(quán)限,也就是上面那句
const roles = res.data.retData.module 這個(gè) module 就是我返回值中目錄權(quán)限的部分,module 就是模塊的意思
3.也就是下一步,在 GenerateRoutes 方法中把 roles 目錄權(quán)限傳進(jìn)去進(jìn)行目錄渲染
然后目錄權(quán)限的數(shù)據(jù)到底長什么樣?先來看下表結(jié)構(gòu)

我代碼中拿到的數(shù)據(jù):

我們要用的只有這個(gè) permission 字段,說簡單點(diǎn),你既可以和我一樣直接拿到目錄對象的所有數(shù)據(jù),也可以單單取這個(gè) permission 字段組成的數(shù)組,看自己習(xí)慣,具體后面判斷邏輯在下面目錄渲染的部分,單單數(shù)組的邏輯會(huì)更加簡單點(diǎn)
/src/store/modules/permission
找到 GenerateRoutes
const permission = {
state: {
routers: constantRouterMap,
addRouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers
state.routers = constantRouterMap.concat(routers)
}
},
actions: {
GenerateRoutes({ commit }, data) {
return new Promise(resolve => {
const { roles } = data
// 權(quán)限對列表進(jìn)行過濾
const accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
commit('SET_ROUTERS', accessedRouters)
resolve()
})
}
}
}對于通用目錄我們不需要管,在原邏輯中,這里通過判斷如果用戶是管理員就直接把整個(gè)權(quán)限目錄都加載,如果不是再進(jìn)行過濾,因?yàn)槲覀冞@完全就通過后臺(tái)控制,包括管理員所以就把判斷去掉了,直接對目錄進(jìn)行過濾
找到 filterAsyncRouter 方法
/**
* 遞歸過濾異步路由表,返回符合用戶角色權(quán)限的路由表
* @param routes asyncRouterMap
* @param roles
*/
function filterAsyncRouter(routes, roles) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(roles, tmp)) {
// 是否存在子節(jié)點(diǎn),存在子節(jié)點(diǎn)說明當(dāng)前節(jié)點(diǎn)為展開欄,并非頁面
if (tmp.children) {
tmp.children = filterAsyncRouter(tmp.children, roles)
// forCheck() 方法遞歸判斷該節(jié)點(diǎn)下是否存在頁面,不存在則隱藏
// true:不存在,false:存在
tmp.hidden = forCheck(tmp.children)
}
res.push(tmp)
}
})
return res
}
/**
* 遞歸子節(jié)點(diǎn),判斷是否存在展示頁面,存在返回 false,不存在返回 true
* @param routes
*/
function forCheck(routes) {
// 設(shè)置默認(rèn)為隱藏
let isHidden = true
// 判斷是否存頁面,不存在說明該節(jié)點(diǎn)下不存在頁面
if (routes != null && routes.length > 0) {
// 循環(huán)子目錄,如果子目錄中不存在需要權(quán)限頁面
// 說明子頁面全是展開欄,隱藏
for (const route of routes) {
// 存在 permission 說明為頁面,不存在說明為展開欄,將子頁面列表繼續(xù)遞歸
if (route.meta && route.meta.permission) {
isHidden = false
return
} else {
isHidden = forCheck(route.children)
}
}
}
return isHidden
}通過循環(huán)權(quán)限目錄通過 hasPermission 方法進(jìn)行判斷
forCheck 是我自己封裝的方法,因?yàn)轫?xiàng)目中不只存在二級(jí)目錄,所以,通過遞歸的方式,判斷子節(jié)點(diǎn)下是否有展示頁,也就是帶 permission 的頁面,如果有,返回 false,沒有返回 true
/**
* 通過meta.role判斷是否與當(dāng)前用戶權(quán)限匹配
* @param roles
* @param route
*/
function hasPermission(roles, route) {
if (route.meta && route.meta.permission) {
return roles.some(role => route.meta.permission.includes(role.permission))
} else {
return true
}
}hasPermission 方法,這里,我們之前加的 permission 參數(shù)就起到作用了
如果有 permission 就進(jìn)行判斷, roles 參數(shù)就是 /src/permission 里傳過來的 module 目錄。
通過 roles.some 循環(huán) roles 別名 role,如果目錄里 includes(包含)這個(gè)目錄權(quán)限,就返回true,否則 false,為 true 的會(huì)被顯示,當(dāng)然如果直接沒有 permission 就說明不需要后臺(tái)管控,就直接 true,這樣目錄就被加載出來了。
到此這篇關(guān)于vue-element-admin 登陸及目錄權(quán)限控制的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)vue-element-admin 登陸及目錄權(quán)限控制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Vue中l(wèi)ocalstorage和sessionstorage的使用
這篇文章主要介紹了詳解Vue中l(wèi)ocalstorage和sessionstorage的使用方法和經(jīng)驗(yàn)心得,有需要的朋友跟著小編參考學(xué)習(xí)下吧。2017-12-12
壓縮Vue.js打包后的體積方法總結(jié)(Vue.js打包后體積過大問題)
大家都知道,Vuejs的 CLI工具 是基于 webpack 來實(shí)現(xiàn)的,所以在項(xiàng)目打包后,會(huì)生成的文件會(huì)很大。 主要原因是 webpack 將我們所有文件都打包成一個(gè)js文件,即使再小的項(xiàng)目,打包之后文件都會(huì)變得很大。 下面講講最近我遇到的相同問題。2020-02-02
vue中el-table格式化el-table-column內(nèi)容的三種方法
本文主要介紹了vue中el-table格式化el-table-column內(nèi)容的三種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
Vue2.0 v-for filter列表過濾功能的實(shí)現(xiàn)
今天小編就為大家分享一篇Vue2.0 v-for filter列表過濾功能的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09
如何隱藏element-ui中tree懶加載葉子節(jié)點(diǎn)checkbox(分頁懶加載效果)
這篇文章主要介紹了如何隱藏element-ui中tree懶加載葉子節(jié)點(diǎn)checkbox(分頁懶加載效果),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
vue實(shí)現(xiàn)3D切換滾動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)偽3D切換滾動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
基于vue3實(shí)現(xiàn)一個(gè)抽獎(jiǎng)小項(xiàng)目
在公司年會(huì)期間我做了個(gè)抽獎(jiǎng)小項(xiàng)目,非常棒,今天把他分享到腳本之家平臺(tái),供大家學(xué)習(xí)參考,對vue3實(shí)現(xiàn)抽獎(jiǎng)小項(xiàng)目感興趣的朋友一起看看吧2023-01-01
Vue2+SpringBoot實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出到csv文件并下載的使用示例
本文主要介紹了Vue2+SpringBoot實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出到csv文件并下載,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-10-10

