1、流行的权限管理方式
1.在路由的meta里定义一个字段,该字段为数组,例如
{
path: "/",
name: "home",
meta: {
title: "页面"
roles:['admin','edit'] // 哪个角色可用
},
component: () =>
import("@/views/home/index.vue")
}
2.把需要权限管理的路由单独放在一个数组里,并不在实例化router对象的时候放进去
3.登录时返回用户的token和当前角色,也就是roles,是‘admin’,还是‘edit’,根据这个关键词筛选数组里的路由,然后使用addRoutes添加进已经实例化的router对象中。从而达到对路由的控制。
优点:能够有效实现菜单管理,权限切换,请求接口简洁
弊端:
1.我们可以把路由看做菜单,也就是说,每个角色拥有的菜单是固定死了,是前端写死了,这并没有真正意义上做到权限管理。
2.使用了addRoutes,动态添加了路由,效率低,有更好的方式不采用addRoutes
3.需要些筛选函数,比如我是‘edit’角色,那我需要递归路由树结构,肯定要筛选所有层级的路由,整合所有的路由地址,再添加进去,非常繁琐。
4.把路由按照需要权限和不需要权限两个模块划分,并非整体,阅读起来不够直观(个人认为)
2、路由基本结构例子
理想中我需要如下功能:
1.创建角色,分配角色所拥有的菜单
2.细粒度够细,具体到某个按钮
3.可任意切换角色
概念 :我们都知道每个路由都有别名name,且唯一(除了分组功能的路由没有name,因为模块分组下有默认页面,默认页面已经有了name)
假如入我们的路由结构如下:(大致看结构)
1.有新闻模块大分组,有公告列表和关于我们两个小分组,没有别名name
2.分组下有各种增删改查操作
3.每个模块下的页面都有别名name
import Vue from "vue";
import Router from "vue-router";
import layout from "@/views/layout/index.vue";
import blank from "@/views/layout/blank.vue";
Vue.use(Router);
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
meta: {
title: "首页"
},
component: layout,
children: [
{
path: "/",
name: "home",
meta: {
title: "欢迎使用"
},
component: () => import("@/views/home/index.vue")
},
{
path: "/articles",
meta: {
title: "文章"
},
component: blank,
children: [
{
path: "/",
meta: {
title: "公告"
},
component: blank,
children: [
{
path: "/",
name: "articles",
meta: {
title: "公告列表"
},
component: () =>
import("@/views/articles/list.vue")
},
{
path: "detail/:id",
name: "articles-detail",
meta: {
title: "公告详细"
},
component: () =>
import("@/views/articles/detail.vue")
},
....
]
},
{
path: "/",
meta: {
title: "关于"
},
component: blank,
children: [
{
path: "about",
name: "about",
meta: {
title: "关于我们"
},
component: () =>
import(
"@/views/articles/about/about.vue"
)
},
{
path: "aboutEdit",
name: "about-edit",
meta: {
title: "编辑关于我们"
},
component: () =>
import(
"@/views/articles/about/aboutEdit.vue"
)
}
]
}
]
}
]
},
{
path: "/login",
name: "login",
meta: {
title: "登录"
},
component: () => import("@/views/login/index.vue")
},
{
path: "/403",
name: "page403",
meta: {
title: "403"
},
component: () => import("@/views/403.vue")
},
{
path: "/*",
name: "page404",
meta: {
title: "404"
},
component: () => import("@/views/404.vue")
}
]
});
3、系统根据路由结构录入路由别名(也叫菜单别名)树结构


这样我们在添加角色的时候,可以轻松的增加或者修改角色

4、定义常用路由别名
例如无论有无权限都可以访问的登录页,404,401页面等,并且增加路由拦截
const whiteList = ["login", "page404", "page403"];
5、获取当前角色,以及角色对应的 路由别名
登录时候,或者getUserInfo时,获取当前角色,以及角色对应的路由别名的一维列表,合并别名列表
const whiteList = ["login", "page404", "page403"];
// 登录的时候,把路由别名列表放在了store的状态里了。
let roleRouter = [...store.getters.roleRouter, ...whiteList];
6、路由拦截设置
设置路由拦截,如果将要访问的路由的别名没有在 roleRouter 当中,那就直接跳转401页面
import router from "./index";
import store from "@/store/index";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
// 常用白名单路由
const whiteList = ["login", "page404", "page403"];
router.beforeEach((to, from, next) => {
NProgress.start();
let roleRouter = [...store.getters.roleRouter, ...whiteList];
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
}
});
}
}
});
router.afterEach(() => {
NProgress.done();
});
7、关于循环菜单
1.根据我们的本地router.js 文件,我们可以循环出左侧菜单的结构
2.增加一个判断就可以实现菜单的管理
let roleRouter = [...store.getters.roleRouter, ...whiteList];
<a-menu-item v-for="(item,index) in router" v-if="roleRouter.includes(item.name)">
<router-link to="/articles">公告列表</router-link>
</a-menu-item>
8、关于权限细粒度问题
1.同样的道理,我们可以在登录或者getUserInfo的时候,获取角色所拥有的所有api一维列表
2.增加一个判断就可以实现权限细粒度管理
let roleApiList = store.getters.roleApiList
// console.log(roleApiList)
// 类似 ['news/list','news/detail','news/add'] 一样的数组
<button v-if="roleApiList.includes('news/add')">
添加新闻
</button>
网友评论