六、撸vue/cli 3.+ 的正确姿势(可控的权限管理)

1、我们的目标是:无限级分权限和菜单

这是我们集团开发的一个CRM系统
1.目的是总部可以控制加盟企业开通的模块
2.加盟企业可以控制旗下园区的模块
3.园区里的管理员可以分配多个管理员(超管和普通管理员)
4.管理员还可以分不同的角色,还可以控制到角色不同的按钮。


六、撸vue/cli 3.+ 的正确姿势(可控的权限管理)_第1张图片
1.jpg

2、如何实现控制模块和控制按钮

1.模块=>菜单=>路由 , 这三个概念合三为一,反过来看就是 : 路由别名=>模块别名=>菜单别名,这样就可以确定,只要有路由地址的页面模块统一都有个名字,这里我们就可以用来判断权限有无了。

2.假如页面有一条数据有删除、发布、存草稿这一类没有页面跳转的按钮(没有路由别名,对应没有模块名),这种我们直接取个“别名”!

注意 :我们都知道每个路由都有别名name,且唯一,所以我们给按钮取“别名”的时候一定不要和路由别名重复,也不要和其它按钮重复,保持唯一

把我们的“别名”一条一条添加在权限表里

六、撸vue/cli 3.+ 的正确姿势(可控的权限管理)_第2张图片
1.jpg

3、权限表都记录哪些信息?

毕竟我们前端只能控制显示隐藏,有和无,但是具体人家接口怎么控制权限,你总的有个东西控制吧!这时候我们就用到了API路由了。
1.添加菜单收集的内容如下,这里可以设置图标,菜单名字,我的图标是用了element里的icon,当然,你也可以用iconfont中的svg,点击下载图标,点击复制svg然后放在这里,然后输出svg图标,但是被后台同学说存的太大,实在不行我们可以做成上传图片。


六、撸vue/cli 3.+ 的正确姿势(可控的权限管理)_第3张图片
image.png

2.添加权限收集的内容如下,这里权限应该挂在菜单上,然后取一个操作名称(例如:删除文章),这里的路由/api别名,其实就是如果是跳转页面,那就是跳转页面的别名,如果不是跳转页面,只是一个按钮请求api,那么就给这个按钮取个名字,或者你给叫给这个操作取“别名”也行。


六、撸vue/cli 3.+ 的正确姿势(可控的权限管理)_第4张图片
image.png

注意一点:有路由的用路由别名,没有的,自己按照路由规则自取自定一个,假装它有路由。

4、如何利用权限表给集团分模块?

当然这里只是分模块,如果你想的话,你甚至可以控制到某个按钮有没有。集团如何给园区分模块也是同理。


六、撸vue/cli 3.+ 的正确姿势(可控的权限管理)_第5张图片
image.png

5、园区如何建立角色?

管理员分配、角色分配、等等都可以分配到具体某个操作按钮。


六、撸vue/cli 3.+ 的正确姿势(可控的权限管理)_第6张图片
image.png

6、说了那么多,代码如何实现?

在我们登录的时候,我们第一件事就是保持用户的user_info,第二件事就是保持别名列表到全局状态nameList这个状态里。(往下翻有技巧保证刷新不丢失。这里先记住往里存。)

这个nameList是菜单+操作的混合体,所以需要自己判断树结构层级,以及从中脱离操作按钮还是菜单。

// 后台的数据结构
{
       name:'news'  // 路由别名,或者按钮别名
       parent_id:0, // 父id
       title:"公司新闻", // 菜单名
       sort:1,  // 排序
       type:1 //1=菜单,2=操作
}
1.关于菜单有无、路由跳转

我们的路由别名存到后台,都是一串别名,所以,这个别名应该是有一个完整的树结构的,这样就构成了我们的菜单结构,以及根据路由别名来做跳转地址。

// 首先这里数据来源肯定是你登录的时候保存到Store,这里肯定用到VUEX,这里不讲了
computed: {
        // 过滤出菜单,排序、组合树结构省略
        menu() {
            return this.$store.getters.nameList.filter(i=>i.type===1);
        },
        // 获得别名列表,过滤省略
        name() {
            return this.$store.getters.nameList.map(i=>i.name);
        }
},
// 循环 menu 菜单绑定上路由跳转和菜单名字,省略循环

         {{ list.title }}

路由拦截,什么页面可以访问,什么不可以访问,不可以访问跳转到哪儿?
因为不是所有路由都是被拦截的,路由白名单也分登录前和登录后

// 用一个专门的文件管理
let name = {
    // 普通白名单
    whiteNameList: ["login", "forgetPwd", "page404", "page403", "demo"],
    // 登录后的白名单
    loginCallbackNameList: ["home"],
}
// 路由拦截写法如下
let roleRouter = [
        ...store.getters.nameList.map(i=>i.name)
        ...name.whiteNameList
];
router.beforeEach((to, from, next) = >{
    if (!to.name || roleRouter.includes(to.name)) {
        next();
    } else {
        if (to.name === "home") {
            next({
                path: "/login",
                replace: true
            });
        } else {
            next({
                path: "/403",
                replace: true,
                query: {
                    noGoBack: true
                }
            });
        }
    }
}
1.如何控制类似“删除”这种按钮显示隐藏

最好的方式是利用 mixins.js混入全局,而且此处不建议做成指令,而是全局methods混入一个$has,

methods: {
        $has(value) {
            return this.$store.getters.nameList.map(i=>i.name).includes(value);
        },
}

如果你的指令写的很强大你可以用指令,如果没那么强大还是建议使用如下写法,但是免不了你要在页面各种判断权限有无来显示不同页面之类的,尤其按钮组合,我就是从用指令,后来弄成指令和methods方法一起用,最后还是觉得methods里的方法好用,看个人爱好了。

v-if="$has('news_delete')"

7、如果页面刷新了,如何保证全局状态nameList不丢失?

这个问题最初也是挺苦恼的,最后我给做了小手脚,当然其它很多状态你也可以利用这个小技巧,用来保持刷新后状态不丢失。
保存别名列表,把它放进本地缓存

mutations: {
       SET_ROLEROUTER: (state, nameList) => {
            state.nameList = nameList;
            window.sessionStorage.setItem(
                "nameList",
                JSON.stringify(nameList)
            );
        },
}

获取的时候,判断state里有没有,如果没有,就从缓存再拉出来,getters.js代码片段如下

nameList: state => {
        let stroageNameList = JSON.parse(
            window.sessionStorage.getItem("nameList")
        );
        if (
            state.user.nameList.length === 0 &&
            (stroageNameList && stroageNameList.length > 0)
        ) {
            store.commit("SET_ROLEROUTER", stroageNameList);
        }
        return state.user.nameList;
    },

8、总结原理

1.利用路由别名做两件事,判断有无模块,控制跳转404还是继续前进。
2.给按钮也取一个别名,判断有无。

你可能感兴趣的:(六、撸vue/cli 3.+ 的正确姿势(可控的权限管理))