此实现方案基于vue框架,并需要依赖vue项目相关的库,router、store等等;前端同学要与后端同学协商,常规是让后端返回一个树结构的菜单数据,并且将所有的涉及权限控制的页面path给
此实现方案基于vue框架,并需要依赖vue项目相关的库,router、store等等;前端同学要与后端同学协商,常规是让后端返回一个树结构的菜单数据,并且将所有的涉及权限控制的页面path给到后端,如果是按钮,需要把所有的按钮 code 码统一下,这是前期工作,很重要。
首先,main.js 引入相关文件
import Vue from 'vue'; import App from './App.vue'; import router from '@/router'; import store from '@/store'; import '@/plugins/permission'; import '@/plugins/directives'; import '@/plugins/auth'; Vue.config.productionTip = false; new Vue({ router, store, render: h => h(App) }).$mount('#app');
在main.js同目录创建 plugins 文件,作为公共文件,在plugins 里创建 permission.js。
import router from @/router'; import store from '@/store'; import { hasMenuAuth } from '@/plugins/auth'; router.beforeEach(async (to, from, next) => { store.dispatch('auth/getAuthData'); // 校验菜单权限 if (hasMenuAuth(to.path)) { next(); } else { next({ path: '/' }); } });
在store目录里创建 auth.js ,getUserMenuList 为定义的接口 api
import { getUserMemuList } from @/api/auth'; /** * 树型数据转列表 * @param {*} tree 树型数据 * @param {*} childrenKey 子节点列表键 */ const convertTreeToList = (tree, childrenKey = 'children') => { if (!Array.isArray(tree)) return []; // 所有的菜单集合 let list = []; // 递归查找 let fn = data => { let origin = data.slice(0); list = list.concat(origin); data.forEach(item => { let children = item[childrenKey]; Array.isArray(children) && fn(children); }); }; fn(tree); return list; }; const state = { // 路由菜单权限 routeAuthList: {}, // 按钮权限列表 authList: {} } }; const mutations = { // 菜单权限列表 SET_ROUTE_AUTH_LIST(state, data) { // 路由权限集合 let routeAuthList = {}; // 按钮权限集合 let buttonAuthList = {}; data.map(item => { // 将所有的 path 存入对象中 if (item.path) { routeAuthList[item.path] = true; } // 将所有的 code 存入对象中 if (item.code) { buttonAuthList[item.code] = true; } }); state.routeAuthList = routeAuthList; state.authList = buttonAuthList; }, }; const actions = { // 获取菜单列表 getAuthData({ commit }) { return getUserMemuList().then(({ data }) => { let list = convertTreeToList(data); commit('SET_ROUTE_AUTH_LIST', list); return data; }); }, }; export default { namespaced: true, state, mutations, actions };
这时,例如在页面中打印,效果是这样的
至此,已经将该用户下所属的权限拉取,并存储在 store 里了,可以全局访问使用。
前面 permission 文件里引用的 hasMenuAuth 方法,需要在 plugins 目录中,创建 auth.js, 并定义下此方法。
import Vue from 'vue'; import store from '@/store'; /** * 校验路由是否有权限 * @param {Array} path 权限 * @return {boolean} */ export function hasMenuAuth(path) { // 无权限配置无需校验 if (!(path && path.length)) return true; const list = store.state.auth.routeAuthList; // 校验是否有权限 let auth = list[path] ? true : false; return auth; } /** * 校验按钮是否有权限 * @param {*} list 权限配置 */ export function hasBtnAuth(list) { // 无权限配置,不校验 if (!list || !list.length) return true; const authList = (store.getters && store.getters.authList) || {}; let hasPermission = false; // // 遍历数组,如果有一个code码存在,则返回true list.map(item => { if (authList[item]) hasPermission = true; }); return hasPermission; } // 挂在权限校验方法 Vue.has = hasBtnAuth; Vue.prototype.$has = hasBtnAuth;
到此处,整个项目路由的拦截就实现了,但目前只拦截了 path,但有页面的按钮,虽然点击后由于做了拦截,让其跳到了默认页。但按钮的还是展示的,这时就需要用到 上面的 hasBtnAuth 方法了。
由于已经在vue实例上挂载了 $has,只需在 vue 组件中使用就好了,可以用在节点里,也可在方法里
当然按钮的显隐,还有进阶版方法,那就是可以注册个自定义指令,在 plugins 目录下创建 directives.js 文件
/** * 按钮权限指令 * 根据vuex下的auth模块的authList按钮code列表判断权限 */ import Vue from 'vue'; import store from '@/store'; /** * 校验是否有权限,无权限删除dom节点 * @param {*} el dom元素 * @param {*} binding 绑定数据 */ function hasAuth(el, binding) { const { value } = binding; const authList = (store.getters && store.getters.authList) || []; if (value && value instanceof Array && value.length > 0) { const list = value; let hasPermission = false; // 遍历数组,如果有一个code码存在,则返回true list.map(item => { if (authList[item]) hasPermission = true; }); if (!hasPermission && value && value.length) { el.parentNode && el.parentNode.removeChild(el); } } } let auth = { inserted: hasAuth, update: hasAuth }; const install = function(Vue) { Vue.directive('auth', auth); }; Vue.use(install);
现在,使用起来更方便了
好了,具体实现方法就是这些,有些地方简述了,但几乎涉及的地方都涉及到了,欢迎指出不足,我也会补全
【文章原创作者:韩国服务器租用 http://www.558idc.com/lg.html 复制请保留原URL】