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

首頁 > 編程 > JavaScript > 正文

基于vue,vue-router, vuex及addRoutes進(jìn)行權(quán)限控制問題

2019-11-19 13:55:49
字體:
供稿:網(wǎng)友

基于vuex, vue-router,vuex的權(quán)限控制教程,完整代碼地址見 https://github.com/linrunzheng/vue-permission-control

接下來讓我們模擬一個(gè)普通用戶打開網(wǎng)站的過程,一步一步的走完整個(gè)流程。

首先從打開本地的服務(wù)localhost:8080開始,我們知道打開后會(huì)進(jìn)入login頁面,那么判斷的依據(jù)是什么。

首先是token。

沒有登陸的用戶是獲取不到token的,而登陸后的角色我們會(huì)將token存到local或者seesionStorage 因此,根據(jù)當(dāng)前有沒有token即可知道是否登陸。

為了存取token并且方便我們操作,可以配和vuex實(shí)現(xiàn)

/* state.js */export default { get UserToken() { return localStorage.getItem('token') }, set UserToken(value) { localStorage.setItem('token', value) }}/* mutation.js */export default { LOGIN_IN(state, token) { state.UserToken = token }, LOGIN_OUT(state) { state.UserToken = '' }}

攔截的判斷

沒有token進(jìn)入需要權(quán)限的頁面:redirect到login頁面

由于我們路由是動(dòng)態(tài)掛載的,包括 ' ' 和404,所以當(dāng)匹配不到路由時(shí),也重定向到login

router.beforeEach((to, from, next) => { if (!store.state.UserToken) { if ( to.matched.length > 0 && !to.matched.some(record => record.meta.requiresAuth) ) { next() } else { next({ path: '/login' }) } } })

好了,此時(shí)用戶打開localhost:8080,默認(rèn)匹配的是''路徑,此時(shí)我們并沒有掛載路由,也沒有token,所以來到了login。

輸入用戶名密碼后,有token了,通過store觸發(fā)* commit('LOGIN_IN')* 來設(shè)置token。

但是還是沒有路由,目前最開始只有l(wèi)ogin路由

/* 初始路由 */export default new Router({ routes: [ { path: '/login', component: Login } ]})/* 準(zhǔn)備動(dòng)態(tài)添加的路由 */export const DynamicRoutes = [ { path: '', component: Layout, name: 'container', redirect: 'home', meta: { requiresAuth: true, name: '首頁' }, children: [ { path: 'home', component: Home, name: 'home', meta: {  name: '首頁' } } ] }, { path: '/403', component: Forbidden }, { path: '*', component: NotFound }]

我們要根據(jù)當(dāng)前用戶的token去后臺獲取權(quán)限。

由于權(quán)限這塊邏輯還挺多,所以在vuex添加了一個(gè)permission模塊來處理權(quán)限。

為了判斷是已有路由列表,需要在vuex的permission模塊存一個(gè)state狀態(tài)permissionList用來判斷,假如permissionList不為null,即已經(jīng)有路由,如果不存在,就需要我們干活了。

router.beforeEach((to, from, next) => { if (!store.state.UserToken) { ... } else { /* 現(xiàn)在有token了 */ if (!store.state.permission.permissionList) { /* 如果沒有permissionList,真正的工作開始了 */ store.dispatch('permission/FETCH_PERMISSION').then(() => { next({ path: to.path }) }) } else { if (to.path !== '/login') { next() } else { next(from.fullPath) } } }})

來看一下 store.dispatch('permission/FETCH_PERMISSION') 都干了什么

actions: { async FETCH_PERMISSION({ commit, state }) { /* 獲取后臺給的權(quán)限數(shù)組 */ let permissionList = await fetchPermission() /* 根據(jù)后臺權(quán)限跟我們定義好的權(quán)限對比,篩選出對應(yīng)的路由并加入到path=''的children */ let routes = recursionRouter(permissionList, dynamicRouter) let MainContainer = DynamicRoutes.find(v => v.path === '') let children = MainContainer.children children.push(...routes) /* 生成左側(cè)導(dǎo)航菜單 */ commit('SET_MENU', children) setDefaultRoute([MainContainer]) /* 初始路由 */ let initialRoutes = router.options.routes /* 動(dòng)態(tài)添加路由 */ router.addRoutes(DynamicRoutes) /* 完整的路由表 */ commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes]) }}

首先,await fetchPermission()獲取后臺給的權(quán)限數(shù)組,格式大概如下

{ "code": 0, "message": "獲取權(quán)限成功", "data": [ { "name": "訂單管理", "children": [ {  "name": "訂單列表" }, {  "name": "生產(chǎn)管理",  "children": [  {  "name": "生產(chǎn)列表"  }    ] }, {  "name": "退貨管理" } ] } ]}

其次根據(jù)我們寫好的路由數(shù)組,進(jìn)行對比,過濾得到我們要的路由

/* 這里是我們寫好的需要權(quán)限判斷的路由 */const dynamicRoutes = [ { path: '/order', component: Order, name: 'order-manage', meta: { name: '訂單管理' }, children: [ { path: 'list', name: 'order-list', component: OrderList, meta: {  name: '訂單列表' } }, { path: 'product', name: 'product-manage', component: ProductManage, meta: {  name: '生產(chǎn)管理' }, children: [  {  path: 'list',  name: 'product-list',  component: ProductionList,  meta: {  name: '生產(chǎn)列表'  }  },  {  path: 'review',  name: 'review-manage',  component: ReviewManage,  meta: {  name: '審核管理'  }  } ] }, { path: 'returnGoods', name: 'return-goods', component: ReturnGoods, meta: {  name: '退貨管理' } } ] }]export default dynamicRoutes

為了對比,我寫好了一個(gè)遞歸函數(shù),用name和meta.name進(jìn)行對比 ,根據(jù)這個(gè)函數(shù)就可以得到我們想要的結(jié)果

/** * * @param {Array} userRouter 后臺返回的用戶權(quán)限json * @param {Array} allRouter 前端配置好的所有動(dòng)態(tài)路由的集合 * @return {Array} realRoutes 過濾后的路由 */export function recursionRouter(userRouter = [], allRouter = []) { var realRoutes = [] allRouter.forEach((v, i) => { userRouter.forEach((item, index) => { if (item.name === v.meta.name) { if (item.children && item.children.length > 0) {  v.children = recursionRouter(item.children, v.children) } realRoutes.push(v) } }) }) return realRoutes}

得到過濾后的數(shù)組后,加入到path為''的children下面

{ path: '', component: Layout, name: 'container', redirect: 'home', meta: { requiresAuth: true, name: '首頁' }, children: [ { path: 'home', component: Home, name: 'home', meta: {  name: '首頁' } }, <!-- 將上面得到的東西加入到這里 --> ... ] }

這個(gè)時(shí)候,path為''的children就是我們左側(cè)的導(dǎo)航菜單了,存到state的sidebarMenu待用。加入到children后,這時(shí)DynamicRoutes就可以加入到路由了。

/* 動(dòng)態(tài)添加路由 */router.addRoutes(DynamicRoutes) /* 初始路由 */let initialRoutes = router.options.routes/* 合并起來,就是完整的路由了 */commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes])

路由添加完了,也就是action操作完畢了,即可在action.then里面調(diào)用 next({ path: to.path })進(jìn)去路由,這里要注意, next里面要傳參數(shù)即要進(jìn)入的頁面的路由信息,因?yàn)閚ext傳參數(shù)后,當(dāng)前要進(jìn)入的路由會(huì)被廢止,轉(zhuǎn)而進(jìn)入?yún)?shù)對應(yīng)的路由,雖然是同一個(gè)路由,這么做主要是為了確保addRoutes生效了。

進(jìn)入路由后,要開始生成左側(cè)菜單,之前我們已經(jīng)存到sidebarMenu了,現(xiàn)在需要做的只是遞歸生成菜單而已,雖然用了element的導(dǎo)航菜單,但是為了遞歸路由,還需要自己封裝一下。這里核心的地方是組件的name,在組件里面有children的地方,又再次使用自己,從而遍歷整個(gè)tree結(jié)構(gòu)的路由。

<template> <div class="menu-container"> <template v-for="v in menuList"> <el-submenu :index="v.name" v-if="v.children&&v.children.length>0" :key="v.name"> <template slot="title">  <i class="iconfont icon-home"></i>  <span>{{v.meta.name}}</span> </template> <el-menu-item-group>  <my-nav :menuList="v.children"></my-nav> </el-menu-item-group> </el-submenu> <el-menu-item :key="v.name" :index="v.name" @click="gotoRoute(v.name)" v-else> <i class="iconfont icon-home"></i> <span slot="title">{{v.meta.name}}</span> </el-menu-item> </template> </div></template><script>export default { name: 'my-nav', props: { menuList: { type: Array, default: function() { return [] } } }, methods: { gotoRoute(name) { this.$router.push({ name }) } }}</script>

刷新頁面后,根據(jù)我們r(jià)outer.beforeEach的判斷,有token但是沒permissionList,我們是會(huì)重新觸發(fā)action去獲取路由的,所以無需擔(dān)心。但是導(dǎo)航菜單active效果會(huì)不見。不過我們已經(jīng)把el-menu-item的key設(shè)置為路由的name,那么我們只要在刷新后,在afterEach把當(dāng)前路由的name賦值給el-menu default-active即可。同理,在afterEach階段獲取所有matched的路由,即可實(shí)現(xiàn)面包屑導(dǎo)航。

if (!store.state.permission.permissionList) { store.dispatch('permission/FETCH_PERMISSION').then(() => { next({ path: to.path }) })} ...router.afterEach((to, from, next) => { var routerList = to.matched store.commit('setCrumbList', routerList) store.commit('permission/SET_CURRENT_MENU', to.name)})

退出登陸后,需要刷新頁面,因?yàn)槲覀兪峭ㄟ^addRoutes添加的,router沒有deleteRoutes這個(gè)api,所以清除token,清除permissionList等信息,刷新頁面是最保險(xiǎn)的。

最后還有一點(diǎn),每次請求得帶上token, 可以對axios封裝一下來處理

var instance = axios.create({ timeout: 30000, baseURL})// 添加請求攔截器instance.interceptors.request.use( function(config) { // 請求頭添加token if (store.state.UserToken) { config.headers.Authorization = store.state.UserToken } return config }, function(error) { return Promise.reject(error) })/* axios請求二次封裝 */instance.get = function(url, data, options) { return new Promise((resolve, reject) => { axios .get(url, data, options) .then( res => {  var response = res.data  if (response.code === 0) {  resolve(response.data)  } else {  Message.warning(response.message)  /* reject(response.message) */  } }, error => {  if (error.response.status === 401) {  Message.warning({  message: '登陸超時(shí),請重新登錄'  })  store.commit('LOGIN_OUT')  window.location.reload()  } else {  Message.error({  message: '系統(tǒng)異常'  })  }  reject(error) } ) .catch(e => { console.log(e) }) })}export default instance

總結(jié)

以上所述是小編給大家介紹的基于vue,vue-router, vuex及addRoutes進(jìn)行權(quán)限控制問題,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對武林網(wǎng)網(wǎng)站的支持!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 新巴尔虎右旗| 新化县| 南平市| 海兴县| 马公市| 东城区| 宜良县| 广西| 运城市| 新营市| 耒阳市| 汾西县| 广东省| 都安| 加查县| 健康| 昌黎县| 江源县| 卢湾区| 长丰县| 六安市| 孙吴县| 柏乡县| 榆中县| 平塘县| 全南县| 涿州市| 梧州市| 泰州市| 麦盖提县| 罗甸县| 尤溪县| 兴海县| 长海县| 昌乐县| 永兴县| 平度市| 定远县| 密山市| 奈曼旗| 二连浩特市|