SpringSecurity6 垃记
直接上代码,明天再编辑
授权逻辑呢
主要是做了url鉴权,我存的是 system:user:list 转成了 /system/user/list
package com.kyokyo.system.config.security;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.security.authorization.AuthorityAuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* @ClassName : CustomAuthorizationManager
* @Description : 自定义AuthorizationManager
* @Author : 段友元(duanyouyuan)
* @Date: 2023年09月21日 18:27:09
*/
@Component
public class CustomAuthorizationManager<HttpServletRequest> implements AuthorizationManager<HttpServletRequest> {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 接口权限映射
*/
private static Map<String, List<GrantedAuthority>> interfacePermissionMappings = new HashMap<>();
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, HttpServletRequest request) {
Authentication auth = authentication.get();
if (null != auth && auth.isAuthenticated() && auth.getAuthorities().size() > 0) {
RequestAuthorizationContext context = (RequestAuthorizationContext) request;
String requestURI = context.getRequest().getRequestURI();
List<GrantedAuthority> grantedAuthorities = interfacePermissionMappings.get(requestURI);
for (GrantedAuthority authority : auth.getAuthorities()) {
if (grantedAuthorities.contains(authority)) {
return new AuthorizationDecision(true);
}
}
}
return new AuthorizationDecision(false);
}
@PostConstruct
public void init() {
// 查出所有菜单、按钮类型的菜单 菜单类型(1.目录 2.菜单 3.按钮)
String queryMenuSql = "select id,menu_perm from sys_menu where menu_type in ('2','3') and menu_perm != '' and menu_perm is not null";
List<Map<String, Object>> menuMaps = jdbcTemplate.queryForList(queryMenuSql);
// 使用菜单ID集合查询菜单及菜单需要的权限
String queryRoleSql = """
select menu_id,role_code from
(select menu_id, role_id from sys_role_menu where menu_id in (:menuIds) ) t
left join sys_role sr on role_id = sr.id
""";
MapSqlParameterSource param = new MapSqlParameterSource();
param.addValue("menuIds", menuMaps.stream().map(m -> m.get("id")).collect(Collectors.toList()));
NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(jdbcTemplate);
List<Map<String, Object>> roleMaps = template.queryForList(queryRoleSql, param);
interfacePermissionMappings = roleMaps.stream()
.collect(Collectors.groupingBy(m -> m.get("menu_id")))
.entrySet().stream().map(entry -> {
Long menuId = (Long) entry.getKey();
AtomicReference<String> interfaceUrl = new AtomicReference<>("");
menuMaps.forEach(menu -> {
if (Objects.equals(menu.get("id"), menuId)) {
interfaceUrl.set(("/" + menu.get("menu_perm")).replaceAll(":", "/"));
}
});
List<Map<String, Object>> roles = entry.getValue();
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
roles.forEach(r -> {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + r.get("role_code"));
grantedAuthorities.add(authority);
});
return new AbstractMap.SimpleEntry<>(interfaceUrl.get(), grantedAuthorities);
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
}
配置呢
@Configuration
public class SecurityConfig {
@Autowired
private CustomAuthorizationManager customAuthorizationManager;
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http.formLogin(withDefaults());
http.authorizeHttpRequests()
.anyRequest()
.access(customAuthorizationManager);
// 获取工厂对象
ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);
// 设置自定义URL权限处理
/*http.apply(new AuthorizeHttpRequestsConfigurer<>(applicationContext))
.withObjectPostProcessor(new ObjectPostProcessor<AuthorizationFilter>() {
@Override
public <O extends AuthorizationFilter> O postProcess(O object) {
return object;
}
});*/
return http.build();
}
}
用户对象呢
package com.kyokyo.system.config.security;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.io.Serial;
import java.util.Collection;
/**
* @Author: 段友元(duanyouyuan)
* @Date: 2023年09月19 11:38:31
* @Description: 自定义用户对象
**/
@Accessors(chain = true)
@Data
public class CustomUserDetails implements UserDetails {
@Serial
private static final long serialVersionUID = 6150234099286074671L;
/**
* 主键
*/
private Long id;
/**
* 账号
*/
private String userAccount;
/**
* 密码
*/
private String password;
/**
* 是否启用(1.是 0.否)
*/
private Boolean enabled;
/**
* 是否删除(1.是 0.否)
*/
private String deleteFlag;
private Collection<? extends GrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.getUserAccount();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return this.enabled;
}
}
查询用户对象呢
package com.kyokyo.system.config.security;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.kyokyo.system.user.entity.User;
import com.kyokyo.system.user.mapper.UserMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Author: 段友元(duanyouyuan)
* @Date: 2023年09月19 11:41:29
* @Description: 自定义用户接口
**/
@Slf4j
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = loadUserByUserName(username);
if (null != user) {
// 查询用户的角色编码集合
List<String> roleCodes = loadRoleCodesByUserId(user.getId());
Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
if (!CollectionUtils.isEmpty(roleCodes)) {
authorities = roleCodes.stream().map(code -> new SimpleGrantedAuthority("ROLE_" + code)).collect(Collectors.toList());
}
return new CustomUserDetails()
.setUserAccount(user.getUserAccount())
.setPassword(user.getPassword())
.setEnabled(user.getEnabled())
.setAuthorities(authorities);
} else {
throw new UsernameNotFoundException("未找到该用户:" + username);
}
}
/**
* 描述:使用账号查询用户信息
* @author 段友元(duanyouyuan)
* @param userName 账号
* @return com.kyokyo.system.user.entity.User
* @create 2023年09月19日 11:54:01
**/
private User loadUserByUserName(String userName) {
return new LambdaQueryChainWrapper<>(userMapper).eq(User::getUserAccount, userName).one();
}
/**
* 描述:使用用户 ID查询用户角色编码集合
* @author 段友元(duanyouyuan)
* @param userId 用户 ID
* @return java.util.List<java.lang.String>
* @create 2023年09月19日 14:18:58
**/
private List<String> loadRoleCodesByUserId(Long userId) {
return userMapper.selectRoleCodesByUser(userId);
}
}
建表语句
/*
Navicat Premium Data Transfer
Source Server : 本机服务
Source Server Type : MySQL
Source Server Version : 80030
Source Host : localhost:3306
Source Schema : kyokyo-boot
Target Server Type : MySQL
Target Server Version : 80030
File Encoding : 65001
Date: 21/09/2023 23:24:35
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu` (
`id` bigint NOT NULL COMMENT '主键',
`parent_id` bigint NOT NULL COMMENT '父级主键',
`menu_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单名',
`menu_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单编码',
`menu_type` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单类型(1.目录 2.菜单 3.按钮)',
`component_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组件路径',
`menu_perm` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单权限',
`menu_sort` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单顺序',
`menu_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '描述',
`enabled` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否启用(1.是 0.否)',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`delete_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否删除(1.是 0.否)',
`created_by` bigint NULL DEFAULT NULL COMMENT '创建人',
`created_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`updated_by` bigint NULL DEFAULT NULL COMMENT '更新人',
`updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_parent_id`(`parent_id` ASC) USING BTREE COMMENT '父级主键',
INDEX `idx_menu_code`(`menu_code` ASC) USING BTREE COMMENT '菜单编码'
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '菜单表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of sys_menu
-- ----------------------------
INSERT INTO `sys_menu` VALUES (1, 0, '系统管理', 'system', '1', NULL, NULL, '100', NULL, '1', NULL, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
INSERT INTO `sys_menu` VALUES (2, 0, '库存管理', 'inventory', '1', NULL, NULL, '200', NULL, '1', NULL, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
INSERT INTO `sys_menu` VALUES (1001, 1, '用户管理', 'user', '2', 'system/user/index', 'system:user:list', '100', NULL, '1', NULL, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
INSERT INTO `sys_menu` VALUES (1002, 1, '角色管理', 'role', '2', 'system/role/index', 'system:role:list', '200', NULL, '1', NULL, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
INSERT INTO `sys_menu` VALUES (1003, 1, '菜单管理', 'menu', '2', 'system/menu/index', 'system:menu:list', '300', NULL, '1', NULL, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` bigint NOT NULL COMMENT '主键',
`role_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色名',
`role_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色编码',
`role_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色描述',
`enabled` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否启用(1.是 0.否)',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`delete_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否删除(1.是 0.否)',
`created_by` bigint NULL DEFAULT NULL COMMENT '创建人',
`created_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`updated_by` bigint NULL DEFAULT NULL COMMENT '更新人',
`updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_role_code`(`role_code` ASC) USING BTREE COMMENT '角色编码'
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, '超级管理员', 'admin', '超级管理员', '1', NULL, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
INSERT INTO `sys_role` VALUES (2, '维护工程师', 'maintenance', '维护工程师', '1', NULL, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
INSERT INTO `sys_role` VALUES (3, '普通用户', 'normal', '普通用户', '1', NULL, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
-- ----------------------------
-- Table structure for sys_role_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu` (
`id` bigint NOT NULL COMMENT '主键',
`role_id` bigint NOT NULL COMMENT '用户ID',
`menu_id` bigint NOT NULL COMMENT '角色ID',
`delete_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否删除(1.是 0.否)',
`created_by` bigint NULL DEFAULT NULL COMMENT '创建人',
`created_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`updated_by` bigint NULL DEFAULT NULL COMMENT '更新人',
`updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_role_id`(`role_id` ASC) USING BTREE COMMENT '角色主键',
INDEX `idx_menu_id`(`menu_id` ASC) USING BTREE COMMENT '菜单主键'
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色菜单中间表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of sys_role_menu
-- ----------------------------
INSERT INTO `sys_role_menu` VALUES (1, 1, 1001, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
INSERT INTO `sys_role_menu` VALUES (2, 2, 1001, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` bigint NOT NULL COMMENT '主键',
`user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名',
`user_account` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '账号',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码',
`user_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '描述',
`enabled` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否启用(1.是 0.否)',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`delete_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否删除(1.是 0.否)',
`created_by` bigint NULL DEFAULT NULL COMMENT '创建人',
`created_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`updated_by` bigint NULL DEFAULT NULL COMMENT '更新人',
`updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '段友元', 'kyokyo', '{noop}123456', '开发账号', '1', NULL, '0', 1, '2023-09-19 09:42:33', 1, '2023-09-19 09:42:35');
INSERT INTO `sys_user` VALUES (2, '貂蝉', 'diaochan', '{noop}123456', '开发账号', '1', NULL, '0', 1, '2023-09-19 09:42:33', 1, '2023-09-19 09:42:35');
INSERT INTO `sys_user` VALUES (3, '西施', 'xishi', '{noop}123456', '开发账号', '1', NULL, '0', 1, '2023-09-19 09:42:33', 1, '2023-09-19 09:42:35');
-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`id` bigint NOT NULL COMMENT '主键',
`user_id` bigint NOT NULL COMMENT '用户ID',
`role_id` bigint NOT NULL COMMENT '角色ID',
`delete_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否删除(1.是 0.否)',
`created_by` bigint NULL DEFAULT NULL COMMENT '创建人',
`created_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`updated_by` bigint NULL DEFAULT NULL COMMENT '更新人',
`updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_user_id`(`user_id` ASC) USING BTREE COMMENT '用户主键',
INDEX `idx_role_id`(`role_id` ASC) USING BTREE COMMENT '角色主键'
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户角色中间表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1, 1, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
INSERT INTO `sys_user_role` VALUES (2, 2, 2, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
INSERT INTO `sys_user_role` VALUES (3, 3, 3, '0', 1, '2023-09-19 09:44:58', 1, '2023-09-19 09:45:02');
SET FOREIGN_KEY_CHECKS = 1;