項目中權限功能

記錄兩個項目中的權限校驗實現方式

1.OKR(一個項目)權限校驗

使用github上開源框架ant-design-pro前端

路由權限的實現方式是經過獲取當前用戶的權限去比對路由表,生成當前用戶具備的權限可訪問的路由表,經過 router.addRoutes 動態掛載到 router 上。vue

OKR中每一個頁面的權限都是動態從後端配置的,能夠在後臺經過一個 tree 或者其它展示形式給每個頁面動態配置權限,以後將這份路由表存儲到後端。該項目中是使用tree實現路由控制。git

1.1後臺返回數據結構

/me 接口,獲得用戶全部信息github

 

 1 //返回的JSON格式
 2 {
 3   data:{
 4     ...//基本信息
 5     permissions:[{
 6     permissionId:"頁面權限id/系統id",
 7     title:'HolliOne',
 8     children:[{
 9          permissionId:'user', //頁面及權限
10           title:'用戶管理',
11         children:[{
12             action: "resetPassword" //資源按鈕級權限
13               title:'重置密碼',
14             ....
15      },...]
16   },...]
17   },
18   message:'請求成功',
19   success:true,
20 }

1.2 前端頁面菜單級權限校驗

當用戶登陸後獲得 permissions,動態生成可訪問頁面vuex

 1 // 前端路由表
 2 const constantRouterComponents = {
 3   // 基礎頁面 layout 必須引入
 4   BasicLayout: BasicLayout,
 5   BlankLayout: BlankLayout,
 6   RouteView: RouteView,
 7   PageView: PageView,
 8 
 9   // 須要動態引入的頁面組件
10   analysis: () => import('@/views/dashboard/Analysis'),
11   workplace: () => import('@/views/dashboard/Workplace'),
12   monitor: () => import('@/views/dashboard/Monitor')
13   // ...more
14 }
View Code
 1 getInfo().then(response => {
 2      const result = response.data
 3      result.role = {}
 4      if (result.permissions[0].children.length > 0) {
 5      let temp = []
 6      const role = result.role
 7      role.permissions = util.findActionArr(result.permissions[0].children,temp)
 8      // const role = result.role
 9      // role.permissions = result.permissions[0].children
10      role.permissions.map(per => {
11      if (per.children != null && per.children.length > 0) {
12             const action = per.children.map(action => { return action.action })
13             per.actionList = action
14        }
15     })
16     // role.permissionList = role.permissions.map(permission => {  return permission.permissionId })
17     let permissionList = [];
18     role.permissionList = util.findArr(result.permissions[0].children, permissionList, 'permissionId')
19     commit('SET_ROLES', result.role)
20     commit('SET_INFO', result)
21     } else {
22     reject(new Error('getInfo: roles must be a non-null array !'))
23     }commit('SET_AVATAR', result.avatar)
24       resolve(response)
25     }).catch(error => {
26        reject(error)
27  })
View Code
 1 //動態生成菜單
 2 router.beforeEach((to, from, next) => {
 3   NProgress.start() // start progress bar
 4 
 5   if (Vue.ls.get(ACCESS_TOKEN)) {
 6     /* has token */
 7     if (to.path === '/user/login') {
 8       next({ path: '/user/userList' })
 9       NProgress.done()
10     } else {
11       if (store.getters.roles.length === 0) {
12         store
13           .dispatch('GetInfo')
14           .then(res => {
15             const roles = res.data && res.data.role
16             store.dispatch('GenerateRoutes', { roles }).then(() => {
17               // 根據roles權限生成可訪問的路由表
18               // 動態添加可訪問路由表
19               router.addRoutes(store.getters.addRouters)
20               const redirect = decodeURIComponent(from.query.redirect || to.path)
21               if (to.path === redirect) {
22                 // hack方法 確保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
23                 next({ ...to, replace: true })
24               } else {
25                 // 跳轉到目的路由
26                 next({ path: '/'+ roles.permissionList[0] })
27               }
28             })
29           })
30           .catch((err) => {
31             console.log(err);
32             notification.error({
33               message: '錯誤',
34               description: '您暫時沒有權限,請聯繫管理員開啓權限'
35             })
36             store.dispatch('Logout').then(() => {
37               next({ path: '/user/login', query: { redirect: to.fullPath } })
38             })
39           })
40       } else {
41         next()
42       }
43     }
44   } else {
45     if (whiteList.includes(to.name)) {
46       // 在免登陸白名單,直接進入
47       next()
48     } else {
49       next({ path: '/user/login', query: { redirect: to.fullPath } })
50       NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
51     }
52   }
53 })
54 
55 //vuex store modules
56 /**
57  * 過濾帳戶是否擁有某一個權限,並將菜單從加載列表移除
58  *
59  * @param permission
60  * @param route
61  * @returns {boolean}
62  */
63 function hasPermission (permission, route) {
64   if (route.meta && route.meta.permission) {
65     let flag = false
66     for (let i = 0, len = permission.length; i < len; i++) {
67       flag = route.meta.permission.includes(permission[i])
68       if (flag) {
69         return true
70       }
71     }
72     return false
73   }
74   return true
75 }
76 //格式化 後端 結構信息並遞歸生成層級路由表
77 function filterAsyncRouter (routerMap, roles) {
78   const accessedRouters = routerMap.filter(route => {
79     if (hasPermission(roles.permissionList, route)) {
80       if (route.children && route.children.length) {
81         route.children = filterAsyncRouter(route.children, roles)
82       }
83       return true
84     }
85     return false
86   })
87   return accessedRouters
88 }
89   actions: {
90     GenerateRoutes ({ commit }, data) {
91       return new Promise(resolve => {
92         const { roles } = data
93         const accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
94         commit('SET_ROUTERS', accessedRouters)
95         resolve()
96       })
97     }
98   }
View Code

1.3 資源/按鈕級權限校驗

封裝了一個按鈕級別權限的自定義指令, v-action後端

 

 1 <!-- eg: 當前頁面爲 user -->
 2 
 3 <template>
 4     <!-- 校驗是否有 user 權限下的 add 操做權限 -->
 5     <a-button v-action:add >添加用戶</a-button>
 6 
 7     <!-- 校驗是否有 user 權限下的 del 操做權限 -->
 8     <a-button v-action:del>刪除用戶</a-button>
 9 
10     <!-- 校驗是否有 user 權限下的 edit 操做權限 -->
11     <a v-action:edit @click="edit(record)">修改</a>
12 </template>
View Code

須要注意的是,指令權限默認從 store 中獲取當前已經登錄的用戶的角色和權限信息進行比對,因此也要對指令權限的獲取和校驗 Action 權限部分進行自定義。數組

在某些狀況下,不適合使用 v-action,例如 Tab 組件,只能經過手動設置 v-if 來實現。cookie

 1 <template>
 2     <a-tabs>
 3         <a-tab-pane v-if="$auth('user.add')" tab="Tab 1">
 4             some context..
 5         </a-tab-pane>
 6         <a-tab-pane v-if="$auth('user.del')" tab="Tab 2">
 7             some context..
 8         </a-tab-pane>
 9         <a-tab-pane v-if="$auth('user.edit')" tab="Tab 3">
10             some context..
11         </a-tab-pane>
12     </a-tabs>
13 </template>
View Code

在 Vue 初始化時,@/utils/helper/permission.js 做爲插件註冊到 Vue 原型鏈上,在 Vue 實例中就能夠用 this.$auth() 方法進行權限判斷。 這裏也要對權限的獲取和校驗 Action 權限部分進行自定義。數據結構

2.另外一個項目的權限校驗

使用iview-admin開源框架app

2.1後臺返回的數據結構

/userInfo接口

 

 1 //接口返回的JSON格式數據
 2 {
 3   data:{
 4     btnSet:['按鈕級權限集合(例如增刪該查以及各類操做)'],
 5     menuSet:['頁面級權限集合,返回字段和前端路由配置一致的頁面就有權限'],
 6     soleSet:['角色集合,該用戶是什麼角色'],
 7     user:{'登陸用戶的基本信息'},
 8   },
 9   msg:'操做成功',
10   state:1,
11   success:true
12 }

2.2前端頁面級權限操做

路由權限的實現方式是經過獲取當前用戶的權限去比對路由表,生成當前用戶具備的權限可訪問的路由表

前端登陸時調用userInfo接口,將權限信息分開存入本地localStorage或者cookies/vuex-store,(就是便於拿到信息的地方)

第一步:過濾頁面權限

 1   /**
 2      * 對一個對象或者數組進行深複製,保證不是以引用賦值
 3     */
 4  cloneObj(obj) {
 5       var str = obj.constructor === Array ? [] : {};
 6       var newobj = obj.constructor === Array ? [] : {};
 7       if (typeof obj !== 'object') {
 8             return;
 9       } else if (window.JSON) {
10           str = JSON.stringify(obj); // 首先將對象序列化
11           newobj = JSON.parse(str); //  而後將對象還原
12         }
13       return newobj;
14  },
15 //過濾路由
16 updateMenulist (state) {
17             // 權限過濾 、
18             let permissions = Cookies.get('permissions');
19             if (permissions === undefined) {
20                 return;
21             }
22             debugger
23             let menuList = [];
24             appRouter.forEach((child, index) => {
25                 // 深複製對象
26             var item = Utils.cloneObj(child);
27             let len = menuList.push(item);
28             // 父類是否存在
29             let parent = JSON.parse(permissions).filter(p => {
30                     if (p === item.name) {
31                 return p;
32             }
33         });
34             if (parent.length > 0) {
35                 let childrenArr = [];
36                 childrenArr = item.children.filter(child => {
37                         var p = JSON.parse(permissions);
38                 for (var i = 0; i < p.length; ++i) {
39                     // 放開測試頁面
40                     if (p[i] === child.name || child.name === 'hollsysTestPage') {
41                         return child;
42                     }
43                 }
44             });
45                 item.children = childrenArr;
46                 // if (childrenArr === undefined || childrenArr.length === 0) {
47                 //     menuList.splice(len - 1, 1);
48                 // }
49             } else {
50                 menuList.splice(len - 1, 1);
51             }
52         });
53             let resut = [];
54             let pArr = JSON.parse(permissions);
55             /**循環遍歷menuList*/
56             if (menuList != null && menuList.length>0) {
57                 for (var i=0;i<menuList.length;i++) {
58                     var temp = menuList[i];
59                     let childarr = [];
60                     childarr = temp.children;/**二級*/
61                     for (var j=0;j<childarr.length;j++) {
62                         var tempj = childarr[j];
63                         /**遍歷三級路由*/
64                         var sanArr = [];
65                         sanArr = tempj.children;
66                         if (sanArr !== undefined) {
67 
68                             for (var k=0;k<sanArr.length;k++) {
69                                 var tempK = sanArr[k];
70                                 var flag = 0;
71                                 for (var q = 0; q < pArr.length; ++q) {
72                                     // 放開測試頁面
73                                     if (pArr[q] === tempK.name) {
74                                         /**刪除sanArr中這個權限*/
75                                         flag=1;
76                                     }
77                                 }
78                                 if (flag == 0) {
79                                     sanArr.splice(k,1);
80                                 }
81                             }
82                         }
83                     }
84                 }
85             }
86             state.menuList = menuList;
87             // 上面routers加全部的appRouters報錯  改成過濾鏈接時動態添加 
88             // state.routers.push(...appRouter);
89             state.routers.push(...menuList);
90  }
View Code

2.3前端按鈕級權限過濾

頁面路由生成,生成按鈕及的權限

在每一個頁面中經過if/v-if判斷按鈕是否顯示

 1  //此角色有什麼操做按鈕權限功能
 2  permissionsBtnSet (name) {
 3      var permissionsBtnSet = Cookies.get('permissionsBtnSet');
 4      var p = JSON.parse(permissionsBtnSet);
 5      for (var i = 0; i < p.length; ++i) {
 6       if (p[i] === name) {
 7          return true;
 8        }
 9     }
10     return false;
11  }
View Code

哈哈哈哈,到此就結束了,能夠生成菜單頁面和操做按鈕,本身記錄一下。

相關文章
相關標籤/搜索