vue-element-admin?登陸及目錄權限控制的實現
登陸
萬事開頭難,做什么事都要有個起點,后面才能更好的進行下去,因此我選擇的起點就是最為直觀的登陸頁面 /login/index.vue
/src/views/login/index
去除那些無關的東西,比如什么 rules 校驗啊,默認的賬號密碼之類的東西,直接看核心登陸方法 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 主要事做一些緩存之類的處理,這里調用了 store 中的 LoginByUsername 把表單內容傳過去,這里我就改了點 catch 把我自己需要的錯誤信息進行提示,其他東西不需要改動
/src/store/modules/user
上面登陸中請求的 LoginByUsername 正是在這
// 用戶名登錄 LoginByUsername({ commit }, userInfo) { const username = userInfo.username.trim() return new Promise((resolve, reject) => { // 請求后臺登陸 loginByUsername(username, userInfo.password).then(response => { const data = response.data if (response.data.errorCode !== 200) { // 登陸失敗,回傳提示信息 reject(data.errorMsg) } // 設置 token,作為用戶已登陸的前端標識,存在 cookie 中 commit('SET_TOKEN', data.retData) setToken(data.retData) resolve() }).catch(error => { reject(error) }) }) },
setToken() 方法會把 token 保存到 cookie 里,很重要
下面有個 GetUserInfo 方法,在你登陸的時候會去獲取你的權限數據
// 獲取用戶信息 GetUserInfo({ commit, state }) { return new Promise((resolve, reject) => { // 請求獲取權限 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) { // 驗證返回的roles是否是一個非空數組 commit('SET_ROLES', data.retData.module) } else { // 當用戶無任何權限時設置 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) }) }) },
不需要知道那個 new Promise 啥的干啥用,反正我不知道,只要知道 getUserInfo 這個方法就行了,這個方法會以上面之前保存的 token 為參數去請求獲取你的用戶權限,原邏輯是沒有權限就跳登陸頁面,我這系統(tǒng)需要,沒權限也有個首頁可看,所以
SET_ROLES 參數給了個“普通用戶”,反正什么值無所謂有值,沒權限就行。
下面 commit 里的參數,分別為,用戶名,頭像,介紹,保留就好,也可自定義。
PS:在每次頁面跳轉時候頁面都會走一個 GetUserInfo ,以此來判斷用戶有沒有失效,因此,我的做法是直接把用戶信息包括權限保存在 redis 里取,不要每次都從庫里查
/src/utils/request.js
此文件是請求與返回攔截器,我們看返回值攔截器
每次你請求從后臺接口返回時,都會經過返回值攔截器,默認的邏輯是返回的 code 不為 20000 時候就會被攔截,這里需要我們改為自己的邏輯,很多人配置都對,點登錄一直 error 就是因為這個原因
// response interceptor service.interceptors.response.use( response => response, /** * 下面的注釋為通過在response里,自定義code來標示請求狀態(tài) * 當code返回如下情況則說明權限有問題,登出并返回到登錄頁 * 如想通過 xmlhttprequest 來狀態(tài)碼標識 邏輯可寫在下面error中 * 以下代碼均為樣例,請結合自生需求加以修改,若不需要,則可刪除 */ // 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() // 為了重新實例化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
接口的請求都會從這里去請求后臺,就不多贅述,基本只需要改動下請求路徑就ok了。
登出 logout 也是,請求保證后臺注銷,前端處理部分也是在 store/modules/user 里的 LogOut 方法,基本不需要改動。
目錄權限
大多數系統(tǒng)都有根據用戶權限,或者說角色,展示相應頁面的要求
/src/router/index
結合框架來實現目錄的控制,如果是傳統(tǒng)項目,一般是把目錄結構整個存在后臺數據庫里,然后前端循環(huán)展示出來,但是這個在這里不需要這么麻煩,只需要把每個頁面對應的權限保存起來就行了
目錄在分為兩個部分 constantRouterMap 與 asyncRouterMap
constantRouterMap:主要是通用部分,每個用戶都有的頁面
asyncRouterMap:需要進行權限過濾的頁面
所以像首頁這種都丟在 constantRouterMap 里,而像權限管理頁面這種放在 asyncRouterMap 里
在目錄上加上 permission 標識,這個是我自定義的唯一標識,用于區(qū)分每個頁面的權限,我這里直接以頁面的路徑為值,因為路徑肯定唯一
{ 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', # 權限標識,每個目錄唯一 permission: '/xxx/xxx', noCache: false } } ] },
然后就只需要在加載目錄時對目錄進行判斷就可以了
/src/permission
這個文件就是整個路由邏輯在這
從這里的邏輯可以看到,登陸后,現在判斷了用戶權限,如果沒權限就會進入之前說到的 GetUserInfo 方法去獲取權限,由于要對目錄進行控制,所以在 GetUserInfo 里我們也需要獲取到目錄的權限列表,只需要獲取到有的就行了,沒有權限的目錄就不需要獲取。
在 GetUserInfo 的最后通過 resolve 方法把返回值返回這個頁面,截圖中 module 就是我獲取到的有權限的目錄列表,然后通過
GenerateRoutes 來生成要加載的目錄,接下來就是改這了
PS:不少人加我 QQ,說不明白這里什么意思,以及不知道要怎樣的目錄數據,我做個簡要的說明。從這個 permission 文件中我們可以看到目錄渲染一共三步:
1. GetUserInfo 中獲取到你的目錄數據(我權限數據全放這個方法里獲取了:用戶數據,目錄權限,數據權限等),但這里主要的就是目錄權限
2.在上門這個 permission.js 目錄渲染的邏輯中獲取 GetUserInfo 中獲取到的目錄權限,也就是上面那句
const roles = res.data.retData.module 這個 module 就是我返回值中目錄權限的部分,module 就是模塊的意思
3.也就是下一步,在 GenerateRoutes 方法中把 roles 目錄權限傳進去進行目錄渲染
然后目錄權限的數據到底長什么樣?先來看下表結構
我代碼中拿到的數據:
我們要用的只有這個 permission 字段,說簡單點,你既可以和我一樣直接拿到目錄對象的所有數據,也可以單單取這個 permission 字段組成的數組,看自己習慣,具體后面判斷邏輯在下面目錄渲染的部分,單單數組的邏輯會更加簡單點
/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 // 權限對列表進行過濾 const accessedRouters = filterAsyncRouter(asyncRouterMap, roles) commit('SET_ROUTERS', accessedRouters) resolve() }) } } }
對于通用目錄我們不需要管,在原邏輯中,這里通過判斷如果用戶是管理員就直接把整個權限目錄都加載,如果不是再進行過濾,因為我們這完全就通過后臺控制,包括管理員所以就把判斷去掉了,直接對目錄進行過濾
找到 filterAsyncRouter 方法
/** * 遞歸過濾異步路由表,返回符合用戶角色權限的路由表 * @param routes asyncRouterMap * @param roles */ function filterAsyncRouter(routes, roles) { const res = [] routes.forEach(route => { const tmp = { ...route } if (hasPermission(roles, tmp)) { // 是否存在子節(jié)點,存在子節(jié)點說明當前節(jié)點為展開欄,并非頁面 if (tmp.children) { tmp.children = filterAsyncRouter(tmp.children, roles) // forCheck() 方法遞歸判斷該節(jié)點下是否存在頁面,不存在則隱藏 // true:不存在,false:存在 tmp.hidden = forCheck(tmp.children) } res.push(tmp) } }) return res } /** * 遞歸子節(jié)點,判斷是否存在展示頁面,存在返回 false,不存在返回 true * @param routes */ function forCheck(routes) { // 設置默認為隱藏 let isHidden = true // 判斷是否存頁面,不存在說明該節(jié)點下不存在頁面 if (routes != null && routes.length > 0) { // 循環(huá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)權限目錄通過 hasPermission 方法進行判斷
forCheck 是我自己封裝的方法,因為項目中不只存在二級目錄,所以,通過遞歸的方式,判斷子節(jié)點下是否有展示頁,也就是帶 permission 的頁面,如果有,返回 false,沒有返回 true
/** * 通過meta.role判斷是否與當前用戶權限匹配 * @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 參數就起到作用了
如果有 permission 就進行判斷, roles 參數就是 /src/permission 里傳過來的 module 目錄。
通過 roles.some 循環(huán) roles 別名 role,如果目錄里 includes(包含)這個目錄權限,就返回true,否則 false,為 true 的會被顯示,當然如果直接沒有 permission 就說明不需要后臺管控,就直接 true,這樣目錄就被加載出來了。
到此這篇關于vue-element-admin 登陸及目錄權限控制的實現的文章就介紹到這了,更多相關vue-element-admin 登陸及目錄權限控制內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解Vue中l(wèi)ocalstorage和sessionstorage的使用
這篇文章主要介紹了詳解Vue中l(wèi)ocalstorage和sessionstorage的使用方法和經驗心得,有需要的朋友跟著小編參考學習下吧。2017-12-12壓縮Vue.js打包后的體積方法總結(Vue.js打包后體積過大問題)
大家都知道,Vuejs的 CLI工具 是基于 webpack 來實現的,所以在項目打包后,會生成的文件會很大。 主要原因是 webpack 將我們所有文件都打包成一個js文件,即使再小的項目,打包之后文件都會變得很大。 下面講講最近我遇到的相同問題。2020-02-02vue中el-table格式化el-table-column內容的三種方法
本文主要介紹了vue中el-table格式化el-table-column內容的三種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-08-08如何隱藏element-ui中tree懶加載葉子節(jié)點checkbox(分頁懶加載效果)
這篇文章主要介紹了如何隱藏element-ui中tree懶加載葉子節(jié)點checkbox(分頁懶加載效果),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07Vue2+SpringBoot實現數據導出到csv文件并下載的使用示例
本文主要介紹了Vue2+SpringBoot實現數據導出到csv文件并下載,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-10-10