本章实现的功能是,某个用户登录时,如何查找该用户的菜单权限
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
} ]
热门工具 换一换