本章實現(xiàn)的功能是,某個用戶登錄時,如何查找該用戶的菜單權(quán)限
Spring security認證過程
1、用戶使用用戶名和密碼進行登錄。
2、Spring
Security將獲取到的用戶名和密碼封裝成一個實現(xiàn)了Authentication接口的UsernamePasswordAuthenticationToken。
3、將上述產(chǎn)生的token對象傳遞給AuthenticationManager進行登錄認證。
4、AuthenticationManager認證成功后將會返回一個封裝了用戶權(quán)限等信息的Authentication對象。
5、通過調(diào)用SecurityContextHolder.getContext().setAuthentication(...)將AuthenticationManager返回的Authentication對象賦予給當前的SecurityContext。
6、認證成功后,用戶就可以繼續(xù)操作去訪問其它受保護的資源了,通過調(diào)用SecurityContextHolder.getContext().getAuthentication()獲取保存在SecurityContext中的Authentication對象進行相關(guān)的權(quán)限鑒定。
系統(tǒng)權(quán)限設(shè)計
設(shè)計基礎(chǔ):任何權(quán)限的需求,都是為廣義的用戶分配角色,角色擁有廣義的權(quán)限。用戶、角色、菜單(權(quán)限)三大核心表,加上用戶角色、角色菜單兩個映射表。就可以通過登錄的用戶來獲取權(quán)限列表,再間接獲取用戶菜單列表。
系統(tǒng)權(quán)限表結(jié)構(gòu)設(shè)計如下
用戶表
CREATE TABLE `crm_sys_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username`
varchar(50) NOT NULL COMMENT '系統(tǒng)用戶名', `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 '狀態(tài) 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='系統(tǒng)用戶表';
角色表
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 '狀態(tài) 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='系統(tǒng)角色表';
菜單表
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 '按鈕權(quán)限', `sequence` int(11) NOT
NULL COMMENT '排序', `isEnable` int(1) DEFAULT NULL COMMENT '狀態(tài) 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='系統(tǒng)菜單表';
用戶與角色關(guān)聯(lián)表
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='系統(tǒng)用戶與角色關(guān)聯(lián)表';
角色與菜單關(guān)聯(lián)表
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='系統(tǒng)角色與菜單關(guān)聯(lián)表';
查找用戶的菜單權(quán)限樹結(jié)構(gòu)
業(yè)務(wù)代理
@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; } /** * 設(shè)置子元素 * @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 -> { //遞歸設(shè)置子元素,多級菜單支持 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);
返回結(jié)果
[ { "id": 1, "parentId": 0, "name": "系統(tǒng)管理", "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
} ]
熱門工具 換一換