权限管理项目总结

权限管理项目

项目地址:https://gitee.com/zheng-linmou/permission-item/tree/master

1.角色分配菜单功能

1.1.获取树形结构的菜单

public class MenuHelper {

    //构建树形结构  sysMenuList全部数据
    public static List<SysMenu> bulidTree(List<SysMenu> sysMenuList) {
        //创建集合封装最终数据
        List<SysMenu> trees = new ArrayList<>();
        //遍历所有菜单集合
        for (SysMenu sysMenu : sysMenuList) {
            // 找到递归入口,parentid=0
            if (sysMenu.getParentId().longValue() == 0) {
                trees.add(findChildren(sysMenu, sysMenuList));
            }
        }
        return trees;
    }

    /**
     * 深度优先搜索
     *
     * @param sysMenu
     * @param treeNodes
     * @return
     */
    //从根节点进行递归查询,查询子节点
    // 判断 id =  parentid是否相同,如果相同是子节点,进行数据封装
    private static SysMenu findChildren(SysMenu sysMenu, List<SysMenu> treeNodes) {
        //数据初始化
        sysMenu.setChildren(new ArrayList<SysMenu>());
        //遍历递归查找
        for (SysMenu it : treeNodes) {
            //获取当前菜单id
            //比对
            if (Long.parseLong(sysMenu.getId()) == it.getParentId()) {
                if (sysMenu.getChildren() == null) {
                    // 进行初始化
                    sysMenu.setChildren(new ArrayList<>());
                }
                // 找他下面的菜单
                sysMenu.getChildren().add(findChildren(it, treeNodes));
            }
        }
        return sysMenu;
    }

}

1.2.根据userId查询所有的role

	/**
     * 根据用户获取角色数据
     *
     * @param userId
     * @return
     */
    @Override
    public Map<String, Object> getRolesByUserId(Long userId) {

        //获取所有角色
        List<SysRole> roles = list(null);
        //根据用户id查询
        List<String> userRoleIds = sysUserRoleService.getRoleIdsByUserId(userId);

        // 如果这个人没有权限的话全部显示为空就可以了
        // 不能为null,必须为空集合
        if(userRoleIds == null) {
            userRoleIds = new ArrayList<>();
        }

        //创建返回的Map
        Map<String, Object> returnMap = new HashMap<>();
        returnMap.put("allRoles", roles);
        returnMap.put("userRoleIds", userRoleIds);
        return returnMap;
    }

1.3.给用户分配角色

	/**
     * 根据用户分配角色
     *
     * @param assginRoleVo
     */
    @Override
    public void doAssign(AssginRoleVo assginRoleVo) {
        // 根据用户id删除原来分配的角色
        LambdaQueryWrapper<SysUserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserRole::getUserId, assginRoleVo.getUserId());
        sysUserRoleService.remove(queryWrapper);

        // 获取所有的角色id
        // 从前端获取用户的选择
        List<String> roleIdList = assginRoleVo.getRoleIdList();
        for (String roleId : roleIdList) {
            if (!StringUtils.isEmpty(roleId)) {
                SysUserRole sysUserRole = new SysUserRole();
                sysUserRole.setUserId(assginRoleVo.getUserId());
                sysUserRole.setRoleId(roleId);
                //保存
                sysUserRoleService.save(sysUserRole);
            }
        }
    }

1.4.给角色分配权限

	/**
     * 给角色分配权限
     *
     * @param assginMenuVo
     */
    @Override
    public void doAssign(AssginMenuVo assginMenuVo) {
        // 先删除原来的
        LambdaQueryWrapper<SysRoleMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysRoleMenu::getRoleId, assginMenuVo.getRoleId());
        sysRoleMenuService.remove(lambdaQueryWrapper);

        // 又重新加入进去
        // 遍历所有已选择的权限id
        for (String menuId : assginMenuVo.getMenuIdList()) {
            if (menuId != null) {
                //创建SysRoleMenu对象
                SysRoleMenu sysRoleMenu = new SysRoleMenu();
                sysRoleMenu.setMenuId(menuId);
                sysRoleMenu.setRoleId(assginMenuVo.getRoleId());
                //添加新权限
                sysRoleMenuService.save(sysRoleMenu);
            }
        }

    }

2.springsecurity

这个就可以使用原来的我单独学的springsecurity来进行改造

3.动态路由

这个根据一下的数据进行修改就可以了总结(cv大法)

1、后端

你需要先构造出三级菜单的类型

在构造我们前端的动态路由

1.2、获取用户的基本信息
	// 用户信息接口
    @GetMapping("info")
    public R info(HttpServletRequest request) {
        Map<String, Object> map = sysUserService.info(request);
        return R.ok().put("data", map);
    }

实现方法

	/**
     * 用户信息接口
     *
     * @param request
     * @return
     */
    @Override
    public Map<String, Object> info(HttpServletRequest request) {
        // 得到token字符串
        String token = request.getHeader("token");

        // 用户名
        String username = JwtHelper.getUsername(token);
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysUser::getUsername, username);
        // 得到用户id
        SysUser sysUser = getOne(lambdaQueryWrapper);


        Map<String, Object> result = new HashMap<>();

        result.put("name", username);
        result.put("avatar", "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
        result.put("roles", "admin");

        // 菜单的权限数据
        List<RouterVo> routerVoList = sysMenuService.getUerMenuList(sysUser.getId());
        result.put("routers", routerVoList);

        // 按钮权限数据
        // 根据用户id获取用户按钮权限
        List<String> permsList = sysMenuService.findUserPermsList(sysUser.getId());
        result.put("buttons", permsList);
        return result;
    }

菜单的权限数据(分析)

  • 我们还要根据不用的用户的来判断超级管理员
	/**
     * 根据用户id查询权限菜单
     *
     * @param userId
     * @return
     */
    @Override
    public List<RouterVo> getUerMenuList(String userId) {
        // admin是超级管理员, 操作所有内容
        List<SysMenu> sysMenuList = null;
        // 如果id是1的话就是超级管理员 就查询全部就可以了
        if ("1".equals(userId)) {
            LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(SysMenu::getStatus, 1);
            lambdaQueryWrapper.orderByDesc(SysMenu::getSortValue);
            // 表示是超级管理员
            sysMenuList = list(lambdaQueryWrapper);
        } else {
            // 不是超级管理员
            // 根据用户id查询权限数据
            sysMenuList = baseMapper.getUerMenuList(userId);

        }

        // 构建是树形的结构
        List<SysMenu> sysMenusTree = MenuHelper.bulidTree(sysMenuList);

        // 需要变成前端路由里面的index.js里面的文件的样式
        List<RouterVo> routerVoList = RouterHelper.buildRouters(sysMenusTree);

        return routerVoList;
    }

普通管理员的菜单查询的sql语句

<select id="getUerMenuList" resultMap="sysMenuMap">
        select
        distinct
        (m.id     ,m.parent_id,m.name,m.type,m.path,m.component,m.perms,m.icon,m.sort_value,m.status,m.create_time,m.update_time,m.is_deleted)
        from sys_menu m
        inner join sys_role_menu rm on rm.menu_id = m.id
        inner join sys_user_role ur on ur.role_id = rm.role_id
        where
        ur.user_id = #{userId}
        and m.status = 1
        and rm.is_deleted = 0
        and ur.is_deleted = 0
        and m.is_deleted = 0
    </select>
1.3.工具类RouterHelper

根据生成的三级菜单来成功生成前端的动态路由

/**
 *根据菜单数据构建路由的工具类
 */
public class RouterHelper {

    /**
     * 根据菜单构建路由
     * @param menus
     * @return
     */
    public static List<RouterVo> buildRouters(List<SysMenu> menus) {
        List<RouterVo> routers = new LinkedList<RouterVo>();
        for (SysMenu menu : menus) {
            RouterVo router = new RouterVo();
            router.setHidden(false);
            router.setAlwaysShow(false);
            router.setPath(getRouterPath(menu));
            router.setComponent(menu.getComponent());
            router.setMeta(new MetaVo(menu.getName(), menu.getIcon()));
            List<SysMenu> children = menu.getChildren();
            //如果当前是菜单,需将按钮对应的路由加载出来,如:“角色授权”按钮对应的路由在“系统管理”下面
            if(menu.getType().intValue() == 1) {
                List<SysMenu> hiddenMenuList = children.stream().filter(item -> !StringUtils.isEmpty(item.getComponent())).collect(Collectors.toList());
                for (SysMenu hiddenMenu : hiddenMenuList) {
                    RouterVo hiddenRouter = new RouterVo();
                    hiddenRouter.setHidden(true);
                    hiddenRouter.setAlwaysShow(false);
                    hiddenRouter.setPath(getRouterPath(hiddenMenu));
                    hiddenRouter.setComponent(hiddenMenu.getComponent());
                    hiddenRouter.setMeta(new MetaVo(hiddenMenu.getName(), hiddenMenu.getIcon()));
                    routers.add(hiddenRouter);
                }
            } else {
                if (!CollectionUtils.isEmpty(children)) {
                    if(children.size() > 0) {
                        router.setAlwaysShow(true);
                    }
                    router.setChildren(buildRouters(children));
                }
            }
            routers.add(router);
        }
        return routers;
    }

    /**
     * 获取路由地址
     *
     * @param menu 菜单信息
     * @return 路由地址
     */
    public static String getRouterPath(SysMenu menu) {
        String routerPath = "/" + menu.getPath();
        if(menu.getParentId().intValue() != 0) {
            routerPath = menu.getPath();
        }
        return routerPath;
    }
}

2、store/modules/user.js

新增菜单及按钮处理

const getDefaultState = () => {
  return {
    token: getToken(),
    name: '',
    avatar: '',

    buttons: [], // 新增
    menus: '' //新增
  }
}
const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar
  },
  
  // 新增
  SET_BUTTONS: (state, buttons) => {
    state.buttons = buttons
  },
  // 新增
  SET_MENUS: (state, menus) => {
    state.menus = menus
  }
}
// get user info
getInfo({ commit, state }) {
  return new Promise((resolve, reject) => {
    getInfo().then(response => {
      const { data } = response

      if (!data) {
        return reject('Verification failed, please Login again.')
      }

      const { name, avatar } = data

      commit('SET_NAME', name)
      commit('SET_AVATAR', avatar)

      commit("SET_BUTTONS", data.buttons)
      commit("SET_MENUS", data.routers)
      resolve(data)
    }).catch(error => {
      reject(error)
    })
  })
}

3、store/getters.js

新增菜单及按钮处理

const getters = {
  sidebar: state => state.app.sidebar,
  device: state => state.app.device,
  token: state => state.user.token,
  avatar: state => state.user.avatar,
  name: state => state.user.name,

  //新增
  buttons: state => state.user.buttons,
  menus: state => state.user.menus
}
export default getters

4、src/router

先在router这个目录下新建两个js文件,开发环境和生产环境导入组件的方式略有不同

_import_production.js

// 生产环境导入组件
module.exports = file => () => import('@/views/' + file + '.vue')

_import_development.js

// 开发环境导入组件
module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+

5、src/permission.js

整体替换该文件

import router from './router'
import store from './store'
import { getToken } from '@/utils/auth'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // 水平进度条提示: 在跳转路由时使用
import 'nprogress/nprogress.css' // 水平进度条样式
import getPageTitle from '@/utils/get-page-title' // 获取应用头部标题的函数
import Layout from '@/layout'
import ParentView from '@/components/ParentView'
const _import = require('./router/_import_'+process.env.NODE_ENV) // 获取组件的方法

NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
  NProgress.start()
// set page title
  document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
  const hasToken = getToken()
  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        try {
          // get user info
          await store.dispatch('user/getInfo')// 请求获取用户信息
          if (store.getters.menus.length < 1) {
            global.antRouter = []
            next()
          }
          const menus = filterAsyncRouter(store.getters.menus)// 1.过滤路由
          console.log(menus)
          router.addRoutes(menus) // 2.动态添加路由
          let lastRou = [{ path: '*', redirect: '/404', hidden: true }]
          router.addRoutes(lastRou)
          global.antRouter = menus // 3.将路由数据传递给全局变量,做侧边栏菜单渲染工作
          next({
            ...to,
            replace: true
          })
          //next()
        } catch (error) {
          // remove token and go to login page to re-login
          console.log(error)
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else { /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

router.afterEach(() => { // finish progress bar
  NProgress.done()
}) // // 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap) {
  const accessedRouters = asyncRouterMap.filter(route => {
    if (route.component) {
      if (route.component === 'Layout') {
        route.component = Layout
      } else if (route.component === 'ParentView') {
        route.component = ParentView
      } else {
        try {
          route.component = _import(route.component)// 导入组件
        } catch (error) {
          debugger
          console.log(error)
          route.component = _import('dashboard/index')// 导入组件
        }
      }
    }
    if (route.children && route.children.length > 0) {
      route.children = filterAsyncRouter(route.children)
    } else {
      delete route.children
    }
    return true
  })
  return accessedRouters
}

6、src/router

删除index.js中自定义的路由,以下注释内容即为要删除的内容

export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },

  // {
  //   path: '/404',
  //   component: () => import('@/views/404'),
  //   hidden: true
  // },

  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: { title: 'Dashboard', icon: 'dashboard' }
    }]
  }


  //添加我们的路由
  // {
  //   path: '/system',
  //   component: Layout,
  //   meta: {
  //     title: '系统管理',
  //     icon: 'el-icon-s-tools'
  //   },
  //   alwaysShow: true,
  //   children: [
  //     {
  //       path: 'sysRole',
  //       component: () => import('@/views/system/sysRole/list'),
  //       meta: {
  //         title: '角色管理',
  //         icon: 'el-icon-s-help'
  //       },
  //     },
  //     {
  //       path: 'sysUser',
  //       component: () => import('@/views/system/sysUser/list'),
  //       meta: {
  //         title: '用户管理',
  //         icon: 'el-icon-s-help'
  //       },
  //     },

  //     {
  //       name: 'sysMenu',
  //       path: 'sysMenu',
  //       component: () => import('@/views/system/sysMenu/list'),
  //       meta: {
  //         title: '菜单管理',
  //         icon: 'el-icon-s-unfold'
  //       },
  //     },

  //     {
  //       path: 'assignAuth',
  //       component: () => import('@/views/system/sysRole/assignAuth'),
  //       meta: {
  //         activeMenu: '/system/sysRole',
  //         title: '角色授权'
  //       },
  //       hidden: true,
  //     }
  //   ]
  // },


  // 404 page must be placed at the end !!!
  // { path: '*', redirect: '/404', hidden: true }
]

7、src/components

在scr/components目录下新建ParentView文件夹,添加index.vue

<template >
  <router-view />
</template>

8、layout/components/SideBar/index.vue

computed: {
  ...mapGetters([
    'sidebar'
  ]),
  routes() {
    //return this.$router.options.routes
    return this.$router.options.routes.concat(global.antRouter)
  },

9、utils/btn-permission.js

在uitls目录添加btn-permission.js文件

import store from '@/store'

/**
 * 判断当前用户是否有此按钮权限
 * 按钮权限字符串 permission 
 */
export default function hasBtnPermission(permission) {
  // 得到当前用户的所有按钮权限
  const myBtns = store.getters.buttons
  // 如果指定的功能权限在myBtns中, 返回true ==> 这个按钮就会显示, 否则隐藏
  return myBtns.indexOf(permission) !== -1
}

10、main.js

//新增
import hasBtnPermission from '@/utils/btn-permission'
Vue.prototype.$hasBP = hasBtnPermission

11、按钮权限控制

$hasBP(‘bnt.sysRole.add’)控制按钮是否显示

如:角色管理添加按钮,我们没让按钮隐藏,而是让按钮不可操作

<el-button type="success" icon="el-icon-plus" size="mini" @click="add" :disabled="$hasBP('bnt.sysRole.add')  === false">添 加</el-button>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值