国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

詳解利用 Vue.js 實(shí)現(xiàn)前后端分離的RBAC角色權(quán)限管理

2019-11-19 15:26:19
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

項(xiàng)目背景:物業(yè)管理后臺(tái),不同角色擁有不同權(quán)限

采用技術(shù):Vue.js + Vuex + Element UI

實(shí)現(xiàn) RBAC 權(quán)限管理需要后端接口支持,這里僅提供前端解決方案。

因代碼篇幅較大,對(duì)代碼進(jìn)行了刪減,文中 “...” 即為省略的一部分代碼。

大致思路:
首先登錄成功后,從后臺(tái)拉取用戶當(dāng)前可顯示的菜單和可用權(quán)限列表,分別將其存入 store 的 nav(菜單導(dǎo)航) 和 auth(用戶可用權(quán)限) 中,在用戶切換路由時(shí),判斷是否存在 auth ,如果不存在,則重新獲取,判斷當(dāng)前訪問(wèn)地址 to.meta.alias 是否在用戶可用權(quán)限列表中,如果不存在,則提示無(wú)權(quán)限,否則進(jìn)入路由。

1. 路由與側(cè)邊菜單分離

側(cè)邊菜單相關(guān)代碼 Main.vue

<template><!-- ... -->  <aside :class="collapsed?'menu-collapsed':'menu-expanded'">    <!--導(dǎo)航菜單-->    <el-menu :default-active="$route.path"         class="el-menu-vertical-aliyun"          @open="handleopen"         @close="handleclose"         @select="handleselect"         :collapse="collapsed"         unique-opened router>      <template v-for="(item,index) in nav">        <!-- 二級(jí)菜單 -->        <el-submenu :index="index+''"              v-if="item.children && item.children.length > 0">          <!-- 二級(jí)菜單頂級(jí) -->          <template slot="title">            <i :class="['icon',item.iconCls]"></i>            <span slot="title">{{item.name}}</span>          </template>          <!-- 二級(jí)菜單下級(jí) -->          <el-menu-item-group>            <!--<span slot="title">{{item.name}}</span>-->            <!-- && child.url-->            <template v-for="child in item.children">              <!--無(wú)三級(jí)菜單-->              <el-menu-item                  :index="child.url"                  :key="child.url"                  v-if="!child.children">                {{child.name}}              </el-menu-item>              <!--有三級(jí)菜單-->              <el-submenu                  :index="child.url"                  :key="child.url"                  v-if="child.children">                <span slot="title">{{child.name}}</span>                <el-menu-item v-for="subChild in child.children"                       :index="subChild.url"                       :key="subChild.url">                  {{subChild.name}}                </el-menu-item>              </el-submenu>            </template>          </el-menu-item-group>        </el-submenu>        <!-- 一級(jí)菜單 -->        <el-menu-item v-if="!item.children"               :index="item.url">          <i :class="['icon',item.iconCls]"></i>          <span slot="title">{{item.name}}</span>        </el-menu-item>        </template>    </el-menu>  </aside><!-- ... --></template><script>  export default {    // ...    computed: {     // 從 Vuex 中獲取導(dǎo)航菜單     nav() {      return this.$store.state.nav;     }    }    // ...  }</script>

2. 路由切換前進(jìn)行鑒權(quán)

路由定義的部分代碼,對(duì)每個(gè)路由添加了 meta 屬性,用于鑒權(quán)。

這里 component 采用了異步引入的方式。

定義路由

// ...// 系統(tǒng)管理{path: '/system',component: Main,name: '系統(tǒng)管理',redirect: '/system/organization',children: [{ path: '/system/organization', component: () => import ('@/views/System/Organization.vue'), name: '組織結(jié)構(gòu)', // requiresAuth 用于確認(rèn)此地址是否需要驗(yàn)證 // alias 用于獲取后端返回rbac權(quán)限對(duì)應(yīng)的前端路由地址和導(dǎo)航菜單圖標(biāo) meta: {requiresAuth: true, alias: 'Pmsadmin/Oragnize/list'}}, {  path: '/system/user',  component: () => import ('@/views/System/User.vue'),  name: '人員管理',  redirect: '/system/user/index',  children: [  {   path: '/system/user/index',   component: () => import ('@/views/System/UserList.vue'),   name: '職員列表',   meta: {requiresAuth: true, alias: 'Pmsadmin/Admin/list'}  }  ] }, {  path: '/system/auth',  component: () => import ('@/views/System/Auth.vue'),  name: '角色管理',  meta: {requiresAuth: true, alias: 'Pmsadmin/Role/list'} }]}// ...

路由鉤子 beforeEach

router.beforeEach((to, from, next) => { document.title = `${configs.title} - ${to.name}`; const {hasAuth, auth} = store.state.user; // 未拿到權(quán)限,則獲取 if (!hasAuth) {  store.dispatch('getUserAuth');  console.log('重新獲取用戶權(quán)限');  // next(); } // 如果未登錄,跳轉(zhuǎn) if (window.localStorage.getItem('IS_LOGIN') === null && to.path !== '/login') {  console.log('未登錄狀態(tài)');  next({   path: '/login',   query: {redirect: to.fullPath}   // 將跳轉(zhuǎn)的路由path作為參數(shù),登錄成功后跳轉(zhuǎn)到該路由  }) } else {  // 需要鑒權(quán)的路由地址  console.log(to, auth.indexOf(to.meta.alias), auth);  if (to.meta.requiresAuth) {   if (auth.indexOf(to.meta.alias) > -1) {    console.log('有權(quán)限進(jìn)入');    next();   } else {    if(auth.length > 0) {     Message.error({      message: '當(dāng)前用戶權(quán)限不足,無(wú)法訪問(wèn)',      showClose: true,     });    } else {     next();    }   }  } else {   next();  } }});

在 Vuex 的 state 中,定義好 nav 對(duì)象

// 登錄用戶信息const user = { name: '', // 用戶名 avatar: '', // 用戶頭像 auth: [], // 用戶權(quán)限 hasAuth: false // 是否已經(jīng)加載用戶權(quán)限};// 導(dǎo)航菜單const nav = [];

通過(guò) action 異步獲取數(shù)據(jù)

// 獲取用戶權(quán)限const getUserAuth = async ({commit}) => { const res = await http.post('YOUR_URL', {}); if (res === null) return; console.log('getUserAuth', res.param); commit('SET_USER_AUTH', res.param.auth); commit('SET_SIDE_NAV', res.param.nav);};

Vuex 中的 mutation 的相關(guān)代碼

// 設(shè)置用戶權(quán)限const SET_USER_AUTH = (state, auth) => { state.user.auth = auth.concat('歡迎使用'); state.user.hasAuth = true;};// 設(shè)置導(dǎo)航菜單const SET_SIDE_NAV = (state, nav) => { // 導(dǎo)航菜單 let _nav = [{  name: '歡迎使用',  url: "/main",  iconCls: 'fa fa-bookmark' }]; // 權(quán)限菜單對(duì)應(yīng)的路由地址 const route = {  "系統(tǒng)管理": {iconCls: 'fa fa-archive', url: ''},  "Pmsadmin/Oragnize/list": {iconCls: '', url: '/system/organization'},  "Pmsadmin/Admin/list": {iconCls: '', url: '/system/user/index'},  "Pmsadmin/Role/list": {iconCls: '', url: '/system/auth'},  "Pmsadmin/Log/record": {iconCls: '', url: '/system/logs'},  "項(xiàng)目管理": {iconCls: 'fa fa-unlock-alt', url: ''},  "Pmsadmin/Project/list": {iconCls: '', url: '/project/list/index'},  "Pmsadmin/House/list": {iconCls: '', url: '/project/house'},  "Pmsadmin/Pack/list": {iconCls: '', url: '/project/pack'},  "廣告位": {iconCls: 'fa fa-edit', url: ''},  "Pmsadmin/Place/list": {iconCls: '', url: '/adsplace/list'},  "投訴建議": {iconCls: 'fa fa-tasks', url: ''},  "Pmsadmin/Scategory/list": {iconCls: '', url: '/complain/type'},  "Pmsadmin/Complain/list": {iconCls: '', url: '/complain/list'},  "Pmsadmin/Suggest/list": {iconCls: '', url: '/complain/suggestion'},  "報(bào)事報(bào)修": {iconCls: 'fa fa-user', url: ''},  "Pmsadmin/Rcategory/list": {iconCls: '', url: '/rcategory/type'},  "Pmsadmin/Rcategory/info": {iconCls: '', url: '/rcategory/public'},  "Pmsadmin/Repair/list": {iconCls: '', url: '/rcategory/personal'},  "便民服務(wù)": {iconCls: 'fa fa-external-link', url: ''},  "Pmsadmin/Bcategory/list": {iconCls: '', url: '/bcategory/type'},  "Pmsadmin/Service/list": {iconCls: '', url: '/bcategory/list'},  "首座推薦": {iconCls: 'fa fa-file-text', url: ''},  "Pmsadmin/stcategory/list": {iconCls: '', url: '/stcategory/type'},  "Pmsadmin/Store/list": {iconCls: '', url: '/stcategory/list'},  "招商租賃": {iconCls: 'fa fa-leaf', url: ''},  "Pmsadmin/Bussiness/list": {iconCls: '', url: '/bussiness/list'},  "Pmsadmin/Company/list": {iconCls: '', url: '/bussiness/company'},  "Pmsadmin/Question/list": {iconCls: '', url: '/bussiness/question'},  "停車找車": {iconCls: 'fa fa-ra', url: ''},  "Pmsadmin/Cplace/list": {iconCls: '', url: '/cplace/cmanage'},  "Pmsadmin/Clist/list": {iconCls: '', url: '/cplace/clist'},  "Pmsadmin/Cquestion/list": {iconCls: '', url: '/cplace/cquestion'}, }; for (let key in nav) {  let item = nav[key];  let _temp = {};  let subItems = []; // 二級(jí)菜單臨時(shí)數(shù)組  if (item.children && item.children.length > 0) {   // 二級(jí)菜單   item.children.forEach(subItem => {    subItems.push(Object.assign({}, {     name: subItem.name || '',     url: route[subItem.url].url || '',     iconCls: route[subItem.url].iconCls || '',    }))   });   // 一級(jí)菜單   _temp = Object.assign({}, {    name: item.name || '',    url: item.url || '',    iconCls: route[item.name].iconCls || '',    children: subItems.slice(0)   });   _nav.push(_temp);  } } state.nav = _nav;};

3. 后端接口返回內(nèi)容

{  "status": 200,  "info": "數(shù)據(jù)查詢成功!",  "param": {    "nav": {      "1": {        "name": "系統(tǒng)管理",        "url": "",        "children": [          {            "name": "組織結(jié)構(gòu)",            "url": "Pmsadmin/Oragnize/list"          },          {            "name": "人員管理",            "url": "Pmsadmin/Admin/list"          },          {            "name": "角色管理",            "url": "Pmsadmin/Role/list"          },          {            "name": "日志管理",            "url": "Pmsadmin/Log/record"          }        ]      },      "61": {        "name": "廣告位",        "url": "",        "children": [          {            "name": "廣告位列表",            "url": "Pmsadmin/Place/list"          }        ]      }    },    "auth": [      "系統(tǒng)管理",      "Pmsadmin/Oragnize/list",      "Pmsadmin/Admin/list",      "Pmsadmin/Role/list",      "Pmsadmin/Log/record",      "廣告位",      "Pmsadmin/Place/list"    ]  }}

存在的問(wèn)題

  • 新增 修改 刪除 按鈕還無(wú)法實(shí)現(xiàn)根據(jù)用戶權(quán)限控制其顯示
  • 代碼上還存在著不足,期待大神能夠有更優(yōu)的解決方案。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 和政县| 镇远县| 江永县| 延庆县| 曲阳县| 贵州省| 囊谦县| 琼海市| 建湖县| 韶关市| 高雄县| 南漳县| 兴文县| 惠东县| 奉新县| 屯门区| 桃源县| 铁岭市| 高邮市| 金秀| 武强县| 甘肃省| 宜昌市| 故城县| 嘉义县| 吴川市| 新野县| 射洪县| 普陀区| 宽甸| 射阳县| 中宁县| 东海县| 郑州市| 山阴县| 建湖县| 桃园市| 万宁市| 南郑县| 息烽县| 九江县|