项目目前采用的是通过前端配置需要权限的路由,然后通过判断过滤出符合当前角色的菜单列表,但是把路由全部都写到前端代码中,在目前看来安全性有所影响,所以改造了下,改造后采用的方式是后台存储菜单资源信息,在后端转化成 Vue-Router
能使用的路由格式,就像下面这样
之前前端配置路由
最终实现的效果是一样的。
src/router/index.js
把之前在前端配置路由删除 src/store/modules/permission.js
如下图增加了 filterAsyncRouter
方法,这个方法就是为了遍历后台传过来的路由数据,进行一些格式上的转换 import { constantRouterMap } from '@/router' import Layout from '@/views/layout/Layout' const permission = { state: { routers: constantRouterMap, apiRouters: [] // 后台接口获取得到的路由(per_resource) }, mutations: { SET_ROUTERS: (state, routers) => { state.apiRouters = routers state.routers = constantRouterMap.concat(routers) } }, actions: { GenerateRoutes({ commit }, data) { return new Promise(resolve => { commit('SET_ROUTERS', data) resolve() }) } } } export const filterAsyncRouter = (routers) => { // 遍历后台传来的路由字符串,转换为组件对象 const backAsyncRouter = routers.filter(router => { if (router.component) { // Layout布局特殊处理 if (router.component === 'Layout') { router.component = Layout } else { const component = router.component router.component = loadView(component) } } if (router.children && router.children.length > 0) { router.children = filterAsyncRouter(router.children) } return true }) return backAsyncRouter } export const loadView = (view) => { // 路由懒加载 return () => import(`@/views/${view}`) } export default permission 复制代码
3.修改 src/permission.js
把之前遍历过滤路由的方法改成上面的方法
BuldTree
类用来处理数据 package com.example.security.util; import com.example.security.entity.Permission; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @Autoor:杨文彬 * @Date:2019/1/18 * @Description: */ @Slf4j public class BulidTree { public static List<Menu> genRoot(List<Permission> permissions){ List<Menu> trees = new ArrayList<Menu>(); permissions.forEach(permission -> { if(permission != null){ List<Permission> permissionList = permission.getChildren(); Menu menu = new Menu(); menu.setName(permission.getPer_name()); menu.setPath(permission.getPer_resource()); if(permission.getPer_parent_id().toString().equals("0")){ //一级菜单的path需要加'/' menu.setPath("/"+permission.getPer_resource()); //判断component是否为空如果是空返回Layout给前端 menu.setComponent(StringUtils.isEmpty(permission.getPer_component()) ?"Layout" : permission.getPer_component()); }else{ menu.setComponent(permission.getPer_component()); } menu.setMeta(new MenuMetaVo(permission.getPer_name(),permission.getPer_icon())); //判断是否有子路由 if(permissionList != null && permissionList.size() != 0){ menu.setAlwaysShow(true); menu.setRedirect("noredirect"); menu.setChildren(genRoot(permissionList)); } else if (permission.getPer_parent_id().toString().equals("0")){ Menu menu1 = new Menu(); menu1.setMeta(menu.getMeta()); menu1.setPath("index"); menu1.setName(menu.getName()); menu1.setComponent(menu.getComponent()); menu.setName(null); menu.setMeta(null); menu.setComponent("Layout"); List<Menu> menuList = new ArrayList<Menu>(); menuList.add(menu1); menu.setChildren(menuList); } trees.add(menu); } }); return trees; } } 复制代码
这个方法主要作用是处理,树形菜单然后转换成 Vue-Router
格式。之前生成树形的方法需要保留不过要修改下里面的参数。
2.增加 MenuMetaVo
主要是为了生成侧边栏的标题,和图标
package com.example.security.util; import lombok.Data; /** * @Autoor:杨文彬 * @Date:2019/1/18 * @Description: */ @Data public class MenuMetaVo { private String title; private String icon; public MenuMetaVo(String title, String icon) { this.title = title; this.icon = icon; } } 复制代码
这样就已经完成了。代码已经更新到 GitHub 上。有问题欢迎随时联系我~
欢迎关注我的个人微信公众号~