VueRouter实现的前端权限控制

提要

前后端分离时为了区分权限往往会由后端进行判断,再由前端动态生成用户的可操作列表。这是我们很早之前的常识。而问题也随之而来——

  • 如果后端不愿配合呢?
  • 发生变动时的协商问题——每增添页面都需后端配置对应路由权限
  • 后端业务逻辑与前端业务逻辑的不一致性

这些问题使得如果非瀑布模型,后期频繁变动的话开发起来会异常困难,像是又回到了当年前后端未分离时的混沌时代;而前后端分离的模式也让双方的分工明确,以分批请求后渲染的模式取代了当初的后台返回,前端也得以处理更复杂的问题;所以我们应该尽可能的将权限控制在自己手中。

权限控制

权限控制本质上就是把原本的 ”个体“ 抽象为 “角色” ,而对 ”角色“ 的权限进行管理,而前端实现方式也有多种,最常见的两种——”路由守卫“ & ”addRoutes“

路由守卫

大家也许都写过这段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
router.beforeEach((to, from, next) => {
var isLogin =
sessionStorage.getItem("USERNAME") &&
sessionStorage.getItem("UUID");

if (isLogin) {
next();
} else {
if (to.path !== "/login") {
next({ path: "/login" });
} else {
next();
}
}
});

旨在将未登录的页面重定向至登陆页面中。同理,我们也可用此前置路由守卫结合路由元信息做权限判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
router.beforeEach((to, from, next) => {
var isLogin =
sessionStorage.getItem("USERNAME") &&
sessionStorage.getItem("UUID"),
permission = valid(to);

if (isLogin) {
if(permission){
next();
} else {
next({ path: "/401" });
}
} else {
if (to.path !== "/login") {
next({ path: "/login" });
} else {
next();
}
}
});

​ 当然我们也可以将 permission 写至路由元信息中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
router.beforeEach((to, from, next) => {
var isLogin =
sessionStorage.getItem("USERNAME") &&
sessionStorage.getItem("UUID");

if (isLogin) {
if(to.meta.hasPermission){
next();
} else {
next({ path: "/401" });
}
} else {
if (to.path !== "/login") {
next({ path: "/login" });
} else {
next();
}
}
});

​ 但是问题随之而来——每经历一次跳转均需要遍历一遍路由(VueRouter是在vue实例化之前就完成挂载的,不方便更改,每次判断时都需完整遍历)

​ 所以我们可以试试新 API ——addRoutes

addRoutes

Dynamically add more routes to the router. The argument must be an Array using the same route config format with the routes constructor option.

创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页面。

当用户登录后,获取用role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路由表。

调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。

使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。