Vue頁面權限控制和動態添加路由


原文轉自:點我

頁面權限控制

頁面權限控制是什么意思呢?

就是一個網站有不同的角色,比如管理員和普通用戶,要求不同的角色能訪問的頁面是不一樣的。如果一個頁面,有角色越權訪問,這時就得做出限制了。

Vue 動態添加路由及生成菜單這是我寫過的一篇文章,
通過動態添加路由和菜單來做控制,不能訪問的頁面不添加到路由表里,這是其中一種辦法。

另一種辦法就是所有的頁面都在路由表里,只是在訪問的時候要判斷一下角色權限。如果有權限就讓訪問,沒有權限就拒絕,跳轉到 404 頁面。

思路:

在每一個路由的 meta 屬性里,將能訪問該路由的角色添加到 roles 里。用戶每次登陸后,將用戶的角色返回。然后在訪問頁面時,把路由的 meta 屬性和用戶的角色進行對比,如果用戶的角色在路由的 roles 里,那就是能訪問,如果不在就拒絕訪問。

代碼示例:

路由信息

routes: [
    {
        path: '/login', name: 'login', meta: { roles: ['admin', 'user'] }, component: () => import('../components/Login.vue') }, { path: 'home', name: 'home', meta: { roles: ['admin'] }, component: () => import('../views/Home.vue') }, ]

頁面控制

// 假設角色有兩種:admin 和 user // 這里是從后台獲取的用戶角色 const role = 'user' // 在進入一個頁面前會觸發 router.beforeEach 事件 router.beforeEach((to, from, next) => { if (to.meta.roles.includes(role)) { next() } else { next({path: '/404'}) } })

登陸驗證

網站一般只要登陸過一次后,接下來該網站的其他頁面都是可以直接訪問的,不用再次登陸。
我們可以通過 token 或 cookie 來實現,下面用代碼來展示一下如何用 token 控制登陸驗證。

 
router.beforeEach((to, from, next) => { // 如果有token 說明該用戶已登陸 if (localStorage.getItem('token')) { // 在已登陸的情況下訪問登陸頁會重定向到首頁 if (to.path === '/login') { next({path: '/'}) } else { next({path: to.path || '/'}) } } else { // 沒有登陸則訪問任何頁面都重定向到登陸頁 if (to.path === '/login') { next() } else { next(`/login?redirect=${to.path}`) } } })

Vue 動態添加路由及生成菜單

寫后台管理系統,估計有不少人遇過這樣的需求:根據后台數據動態添加路由和菜單。
為什么這么做呢?因為不同的用戶有不同的權限,能訪問的頁面是不一樣的。
在網上找了好多資料,終於想到了解決辦法。

動態生成路由

利用 vue-router 的 addRoutes 方法可以動態添加路由。

先看一下官方介紹:

router.addRoutes

router.addRoutes(routes: Array<RouteConfig>)

動態添加更多的路由規則。參數必須是一個符合 routes 選項要求的數組。

舉個例子:

const router = new Router({ routes: [ { path: '/login', name: 'login', component: () => import('../components/Login.vue') }, {path: '/', redirect: '/home'}, ] })

上面的代碼和下面的代碼效果是一樣的

const router = new Router({ routes: [ {path: '/', redirect: '/home'}, ] }) router.addRoutes([ { path: '/login', name: 'login', component: () => import('../components/Login.vue') } ])

在動態添加路由的過程中,如果有 404 頁面,一定要放在最后添加,否則在登陸的時候添加完頁面會重定向到 404 頁面。

類似於這樣,這種規則一定要最后添加。

{path: '*', redirect: '/404'}

動態生成菜單

假設后台返回來的數據長這樣

// 左側菜單欄數據
menuItems: [ { name: 'home', // 要跳轉的路由名稱 不是路徑 size: 18, // icon大小 type: 'md-home', // icon類型 text: '主頁' // 文本內容 }, { text: '二級菜單', type: 'ios-paper', children: [ { type: 'ios-grid', name: 't1', text: '表格' }, { text: '三級菜單', type: 'ios-paper', children: [ { type: 'ios-notifications-outline', name: 'msg', text: '查看消息' }, { type: 'md-lock', name: 'password', text: '修改密碼' }, { type: 'md-person', name: 'userinfo', text: '基本資料', } ] } ] } ]

來看看怎么將它轉化為菜單欄,我在這里使用了 iview 的組件,不用重復造輪子。

<!-- 菜單欄 -->
<Menu ref="asideMenu" theme="dark" width="100%" @on-select="gotoPage" accordion :open-names="openMenus" :active-name="currentPage" @on-open-change="menuChange"> <!-- 動態菜單 --> <div v-for="(item, index) in menuItems" :key="index"> <Submenu v-if="item.children" :name="index"> <template slot="title"> <Icon :size="item.size" :type="item.type"/> <span v-show="isShowAsideTitle">{{item.text}}</span> </template> <div v-for="(subItem, i) in item.children" :key="index + i"> <Submenu v-if="subItem.children" :name="index + '-' + i"> <template slot="title"> <Icon :size="subItem.size" :type="subItem.type"/> <span v-show="isShowAsideTitle">{{subItem.text}}</span> </template> <MenuItem class="menu-level-3" v-for="(threeItem, k) in subItem.children" :name="threeItem.name" :key="index + i + k"> <Icon :size="threeItem.size" :type="threeItem.type"/> <span v-show="isShowAsideTitle">{{threeItem.text}}</span> </MenuItem> </Submenu> <MenuItem v-else v-show="isShowAsideTitle" :name="subItem.name"> <Icon :size="subItem.size" :type="subItem.type"/> <span v-show="isShowAsideTitle">{{subItem.text}}</span> </MenuItem> </div> </Submenu> <MenuItem v-else :name="item.name"> <Icon :size="item.size" :type="item.type" /> <span v-show="isShowAsideTitle">{{item.text}}</span> </MenuItem> </div> </Menu>

代碼不用看得太仔細,理解原理即可,其實就是通過三次 v-for 不停的對子數組進行循環,生成三級菜單。

動態菜單這樣就可以實現了。

動態路由,因為上面已經說過了用 addRoutes 來實現,現在看看具體怎么做。

首先,要把項目所有的頁面路由都列出來,再用后台返回來的數據動態匹配,能匹配上的就把路由加上,不能匹配上的就不加。 最后把這個新生成的路由數據用 addRoutes 添加到路由表里。

const asyncRoutes = { 'home': { path: 'home', name: 'home', component: () => import('../views/Home.vue') }, 't1': { path: 't1', name: 't1', component: () => import('../views/T1.vue') }, 'password': { path: 'password', name: 'password', component: () => import('../views/Password.vue') }, 'msg': { path: 'msg', name: 'msg', component: () => import('../views/Msg.vue') }, 'userinfo': { path: 'userinfo', name: 'userinfo', component: () => import('../views/UserInfo.vue') } } // 傳入后台數據 生成路由表 menusToRoutes(menusData) // 將菜單信息轉成對應的路由信息 動態添加 function menusToRoutes(data) { const result = [] const children = [] result.push({ path: '/', component: () => import('../components/Index.vue'), children, }) data.forEach(item => { generateRoutes(children, item) }) children.push({ path: 'error', name: 'error', component: () => import('../components/Error.vue') }) // 最后添加404頁面 否則會在登陸成功后跳到404頁面 result.push( {path: '*', redirect: '/error'}, ) return result } function generateRoutes(children, item) { if (item.name) { children.push(asyncRoutes[item.name]) } else if (item.children) { item.children.forEach(e => { generateRoutes(children, e) }) } }

所有的代碼實現,我都放在 github 上,動態菜單的實現放在這個項目下的 src/components/Index.vuesrc/permission.js 和 src/utils/index.js

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM