SpringBoot-Security-用户权限分配-查找用户的菜单权限

简介: 本章实现的功能是,某个用户登录时,如何查找该用户的菜单权限 Spring security认证过程 1、用户使用用户名和密码进行登录。2、Spring Security将获取到的用户名和密码封装成一个实现了Authentication接口的UsernamePasswordAuthenticationToken。

本章实现的功能是,某个用户登录时,如何查找该用户的菜单权限

Spring security认证过程

1、用户使用用户名和密码进行登录。
2、Spring Security将获取到的用户名和密码封装成一个实现了Authentication接口的UsernamePasswordAuthenticationToken。
3、将上述产生的token对象传递给AuthenticationManager进行登录认证。
4、AuthenticationManager认证成功后将会返回一个封装了用户权限等信息的Authentication对象。
5、通过调用SecurityContextHolder.getContext().setAuthentication(...)将AuthenticationManager返回的Authentication对象赋予给当前的SecurityContext。
6、认证成功后,用户就可以继续操作去访问其它受保护的资源了,通过调用SecurityContextHolder.getContext().getAuthentication()获取保存在SecurityContext中的Authentication对象进行相关的权限鉴定。

系统权限设计

设计基础:任何权限的需求,都是为广义的用户分配角色,角色拥有广义的权限。用户、角色、菜单(权限)三大核心表,加上用户角色、角色菜单两个映射表。就可以通过登录的用户来获取权限列表,再间接获取用户菜单列表。

系统权限表结构设计如下

用户表

CREATE TABLE `crm_sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '系统用户名',
`password` varchar(60) NOT NULL COMMENT '密码',
`nickname` varchar(255) DEFAULT NULL COMMENT '昵称',
`headImgUrl` varchar(255) DEFAULT NULL COMMENT '头像',
`phone` varchar(11) DEFAULT NULL COMMENT '手机号',
`telephone` varchar(30) DEFAULT NULL COMMENT '电话',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
`birthday` varchar(10) DEFAULT NULL COMMENT '生日',
`sex` tinyint(1) DEFAULT NULL COMMENT '性别',
`isEnable` int(1) DEFAULT NULL COMMENT '状态 0.已停用 1.正常',
`isDel` int(1) DEFAULT NULL COMMENT '是否删除(0.已删除 1.正常)',
`createTime` varchar(22) DEFAULT NULL,
`updateTime` varchar(22) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='系统用户表';

角色表

CREATE TABLE `crm_sys_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '角色名称',
`description` varchar(100) DEFAULT NULL COMMENT '描述',
`isEnable` tinyint(1) DEFAULT NULL COMMENT '状态 0.已停用 1.正常',
`isDel` tinyint(1) DEFAULT NULL COMMENT '是否删除(0.已删除 1.正常)',
`createTime` varchar(22) DEFAULT NULL,
`updateTime` varchar(22) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='系统角色表';

菜单表

CREATE TABLE `crm_sys_menu` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parentId` int(11) NOT NULL COMMENT '上级菜单',
`name` varchar(50) NOT NULL COMMENT '菜单名称',
`css` varchar(30) DEFAULT NULL COMMENT '图标样式',
`href` varchar(1000) DEFAULT NULL COMMENT '链接',
`type` tinyint(1) NOT NULL COMMENT '菜单类型 1:菜单 2:按钮',
`permission` varchar(50) DEFAULT NULL COMMENT '按钮权限',
`sequence` int(11) NOT NULL COMMENT '排序',
`isEnable` int(1) DEFAULT NULL COMMENT '状态 0.已停用 1.正常',
`isDel` int(1) DEFAULT NULL COMMENT '是否删除(0.已删除 1.正常)',
`createTime` varchar(22) DEFAULT NULL,
`updateTime` varchar(22) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COMMENT='系统菜单表';

用户与角色关联表

CREATE TABLE `crm_sys_user_role` (
`userId` int(11) NOT NULL,
`roleId` int(11) NOT NULL,
PRIMARY KEY (`userId`,`roleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统用户与角色关联表';

角色与菜单关联表

CREATE TABLE `crm_sys_role_menu` (
`roleId` int(11) NOT NULL,
`menuId` int(11) NOT NULL,
PRIMARY KEY (`roleId`,`menuId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统角色与菜单关联表';

查找用户的菜单权限树结构

业务代理

@GetMapping("/current")
public List<SysMenuDto> menuCurrent() {
    LoginUser loginUser = UserUtil.getLoginUser();
    Long id = Long.valueOf(String.valueOf(loginUser.getId()));
    List<SysMenuDto> list = iSysMenuService.listByUserId(id);
    final List<SysMenuDto> menus = list.stream().filter(l -> l.getType().equals(1))
            .collect(Collectors.toList());
    //支持多级菜单
    List<SysMenuDto> firstLevel = menus.stream().filter(p -> p.getParentId().equals(0)).collect(Collectors.toList());
    firstLevel.parallelStream().forEach(m -> {
        setChild(m, menus);
    });
    return firstLevel;
}

/**
 * 设置子元素
 * @param m
 * @param menus
 */
private void setChild(SysMenuDto m, List<SysMenuDto> menus) {
    List<SysMenuDto> child = menus.parallelStream().filter(a -> a.getParentId().equals(m.getId())).collect(Collectors.toList());
    m.setChild(child);
    if (!CollectionUtils.isEmpty(child)) {
        child.parallelStream().forEach(c -> {
            //递归设置子元素,多级菜单支持
            setChild(c, menus);
        });
    }
}

Authentication公用类

public class UserUtil {

public static LoginUser getLoginUser() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication != null) {
        if (authentication instanceof AnonymousAuthenticationToken) {
            return null;
        }

        if (authentication instanceof UsernamePasswordAuthenticationToken) {
            return (LoginUser) authentication.getPrincipal();
        }
    }

    return null;
}

}

sql代码

@Select("select distinct m.* " +
        "from crm_sys_menu m " +
        "inner join crm_sys_role_menu rm on m.id = rm.menuId " +
        "inner join crm_sys_user_role ru on ru.roleId = rm.roleId " +
        "where isDel = 1 and isEnable = 1 and ru.userId = #{userId} order by m.sequence")
List<CrmSysMenuPo> listByUserId(Long userId);

返回结果

[
{
"id": 1,
"parentId": 0,
"name": "系统管理",
"css": "fa-gears",
"href": "",
"type": 1,
"permission": "",
"sequence": 1,
"isEnable": true,
"isDel": true,
"createTime": "2017-10-05 21:59:18",
"child": [
  {
    "id": 2,
    "parentId": 1,
    "name": "用户",
    "css": "fa-users",
    "href": "sys/user/queryList",
    "type": 1,
    "permission": "",
    "sequence": 101,
    "isEnable": true,
    "isDel": true,
    "createTime": "2017-10-05 21:59:18",
    "child": [
      
    ],
    "serialVersion": -123142
  },
  {
    "id": 3,
    "parentId": 1,
    "name": "菜单",
    "css": "fa-cog",
    "href": "sys/menu/queryList",
    "type": 1,
    "permission": "",
    "sequence": 102,
    "isEnable": true,
    "isDel": true,
    "createTime": "2017-10-05 21:59:18",
    "child": [
      
    ],
    "serialVersion": -123142
  },
  {
    "id": 4,
    "parentId": 1,
    "name": "角色",
    "css": "fa-user-secret",
    "href": "sys/role/queryList",
    "type": 1,
    "permission": "",
    "sequence": 103,
    "isEnable": true,
    "isDel": true,
    "createTime": "2017-10-05 21:59:18",
    "child": [
      
    ],
    "serialVersion": -123142
  }
],
"serialVersion": -123142
}
]
目录
相关文章
|
26天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
132 1
|
10天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
90 62
|
8天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
23 2
|
27天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第8天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建并配置 Spring Boot 项目,实现后端 API 和安全配置。接着,使用 Ant Design Pro Vue 脚手架创建前端项目,配置动态路由和菜单,并创建相应的页面组件。最后,通过具体实践心得,分享了版本兼容性、安全性、性能调优等注意事项,帮助读者快速搭建高效且易维护的应用框架。
38 3
|
28天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第7天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建 Spring Boot 项目并配置 Spring Security。接着,实现后端 API 以提供菜单数据。在前端部分,使用 Ant Design Pro Vue 脚手架创建项目,并配置动态路由和菜单。最后,启动前后端服务,实现高效、美观且功能强大的应用框架。
34 2
|
3月前
|
JavaScript 安全 Java
【绝密攻略】揭秘Spring Boot与Ant Design Pro Vue的终极结合:打造梦幻般的动态路由与菜单管理,颠覆你的前后端分离世界!
【8月更文挑战第9天】随着前后端分离趋势的发展,构建高效且易维护的框架至关重要。本文介绍如何利用Spring Boot与Ant Design Pro Vue打造带有动态路由和菜单的应用。首先需安装Node.js、NPM及Java开发工具;接着通过Spring Initializr初始化含Web和Security依赖的项目,并配置Spring Security。后端API提供菜单数据,而前端则基于这些数据动态生成路由和菜单。通过具体步骤演示整个流程,包括创建Controller、配置动态路由、设置菜单等。此外还分享了实践心得,强调版本兼容性、安全性等方面的重要性。
135 1
|
5月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的疫情物资捐赠和分配系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的疫情物资捐赠和分配系统附带文章源码部署视频讲解等
26 0
|
SQL Java 数据库
微服务技术系列教程(39)- SpringBoot -RBAC权限模型
微服务技术系列教程(39)- SpringBoot -RBAC权限模型
221 0
|
6月前
|
存储 安全 前端开发
基于springboot的疫情物资捐赠和分配系统
基于springboot的疫情物资捐赠和分配系统
|
6月前
|
JavaScript 安全 Java
Spring Boot 和 Vue.js 实现的前后端分离的用户权限管理系统
Spring Boot 和 Vue.js 实现的前后端分离的用户权限管理系统
165 0