Spring Security 框架篇-深入了解 Spring Security 的授权核心功能(RBAC 权限模型、自定义异常处理器、校验权限方法)
🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍
文章目录
1.0 权限系统
1.1 引入
1.2 RBAC 权限模型
1.3 数据库设计
2.0 Spring Security 核心功能-授权
2.1 思路分析
2.2 编写 SQL 语句
2.3 将用户权限进行封装
2.4 获取用户权限
2.5 启动预授权
3.0 自定义异常处理器
4.0 自定义校验权限方法
1.0 权限系统
在 Java 开发中,Spring Security 是一个非常强大的框架,用于处理应用程序的安全性。它不仅提供了认证(Authentication)功能,还提供了授权(Authorization)功能,确保用户只能访问他们被授权的资源。
Spring Security 框架中对认证功能进行介绍:
Spring Security 框架篇-深入了解 Spring Security 的认证功能流程和自定义实现登录接口(实现自定义认证过滤器、登出功能)-CSDN博客
1.1 引入
Spring Security 的授权功能主要围绕着几个核心概念构建:
1)权限(Permissions):
权限是最低级别的安全控制,通常与特定的操作或资源相关联。例如,read、write、delete等权限可以被分配给特定的数据对象或业务操作。
2)角色(Roles):
角色是一组权限的集合。在应用中,通常会根据职责的不同来定义不同的角色,如管理员、普通用户、访客等。每个角色拥有一系列权限,这些权限定义了该角色可以执行的操作。
3)访问决策管理器(Access Decision Manager):
这个组件负责决定是否允许请求访问受保护的资源。它基于配置的策略(如一致同意、多数同意等)来评估所有相关的权限和角色。
4)投票者(Voters):
投票者是访问决策管理器的一部分,它们根据用户的权限对访问请求进行投票。投票结果影响最终的访问决策。
5)方法安全(Method Security):
Spring Security 提供了在方法级别上实现细粒度安全控制的能力。通过使用注解如 @PreAuthorize 和 @PostAuthorize,可以为特定的方法调用设置访问控制规则。
6)URL 安全(URL Security):
通过配置 HTTP 请求的安全性,可以限制对特定 URL 模式的访问。这通常是通过在 HttpSecurity 配置中定义匹配模式和相应的访问规则来实现的。
1.2 RBAC 权限模型
RBAC,即基于角色的访问控制,是一种广泛使用的安全模型,它将权限与角色关联起来,而不是直接与用户关联。这样做的好处包括但不限于:
简化管理:通过管理少量的角色及其权限,而不是大量的个人用户权限,大大减少了管理工作量。
提高灵活性:当组织结构或业务需求发生变化时,可以通过调整角色和权限来快速适应,而不需要逐个修改用户权限。
增强安全性:通过最小权限原则,每个用户只拥有完成其工作所需的最少权限,从而减少潜在的安全风险。
在 Spring Security 中实现 RBAC 模型通常涉及以下步骤:
定义角色:根据应用的需求定义不同的角色。
分配权限:为每个角色分配适当的权限。
用户角色映射:将用户与一个或多个角色关联起来。
配置安全策略:利用 Spring Security 提供的工具(如 @Secured 注解、@PreAuthorize 表达式等)来定义哪些角色可以访问哪些资源或执行哪些操作。
通过这种方式,Spring Security 可以有效地支持复杂的权限管理和访问控制需求,帮助开发者构建更加安全可靠的应用程序。
1.3 数据库设计
如果将其分解进行数据库设计,RBAC0基本模型可以分成以下五个部分:
1)User(用户):每个用户都有唯一的UID识别,并被授予不同的角色
2)Role(角色):不同角色具有不同的权限
3)Permission(权限):访问权限
4)用户-角色映射:用户和角色之间的映射关系
5)角色-权限映射:角色和权限之间的映射
转换成数据库表的话大致如下所示:
这就可以实现给用户进行授权相关的权限。
根据业务需求,对数据库进行设计:
-- ---------------------------- -- Table structure for sys_menu -- ---------------------------- DROP TABLE IF EXISTS `sys_menu`; CREATE TABLE `sys_menu` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `menu_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'NULL' COMMENT '菜单名', `path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '路由地址', `component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '组件路径', `visible` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '菜单状态(0显示 1隐藏)', `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '菜单状态(0正常 1停用)', `perms` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '权限标识', `icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '#' COMMENT '菜单图标', `create_by` bigint(0) NULL DEFAULT NULL, `create_time` datetime(0) NULL DEFAULT NULL, `update_by` bigint(0) NULL DEFAULT NULL, `update_time` datetime(0) NULL DEFAULT NULL, `del_flag` int(0) NULL DEFAULT 0 COMMENT '是否删除(0未删除 1已删除)', `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '菜单表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_menu -- ---------------------------- INSERT INTO `sys_menu` VALUES (1, '部门管理', ' dept', ' system/dept/index', '0', '0', 'system:dept:list', '#', NULL, NULL, NULL, NULL, 0, NULL); INSERT INTO `sys_menu` VALUES (2, ' 测试', 'test', 'system/test/index', '0', '0', 'system:test:list', '#', NULL, NULL, NULL, NULL, 0, NULL); -- ---------------------------- -- Table structure for sys_role -- ---------------------------- DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, `role_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色权限字符串', `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '角色状态(0正常 1停用)', `del_flag` int(0) NULL DEFAULT 0 COMMENT 'del_flag', `create_by` bigint(0) NULL DEFAULT NULL, `create_time` datetime(0) NULL DEFAULT NULL, `update_by` bigint(0) NULL DEFAULT NULL, `update_time` datetime(0) NULL DEFAULT NULL, `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '角色表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_role -- ---------------------------- INSERT INTO `sys_role` VALUES (1, 'CEO', 'ceo', '0', 0, NULL, NULL, NULL, NULL, NULL); INSERT INTO `sys_role` VALUES (2, 'Coder', ' coder', '0', 0, NULL, NULL, NULL, NULL, NULL); -- ---------------------------- -- Table structure for sys_role_menu -- ---------------------------- DROP TABLE IF EXISTS `sys_role_menu`; CREATE TABLE `sys_role_menu` ( `role_id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '角色ID', `menu_id` bigint(0) NOT NULL DEFAULT 0 COMMENT '菜单id', PRIMARY KEY (`role_id`, `menu_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_role_menu -- ---------------------------- INSERT INTO `sys_role_menu` VALUES (1, 1); INSERT INTO `sys_role_menu` VALUES (1, 2); INSERT INTO `sys_role_menu` VALUES (2, 2); -- ---------------------------- -- Table structure for sys_user -- ---------------------------- DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '主键', `user_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'NULL' COMMENT '用户名', `nick_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'NULL' COMMENT '昵称', `password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'NULL' COMMENT '密码', `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '账号状态(0正常 1停用)', `email` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '邮箱', `phonenumber` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '手机号', `sex` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户性别(0男,1女,2未知)', `avatar` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '头像', `user_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '1' COMMENT '用户类型(0管理员,1普通用户)', `create_by` bigint(0) NULL DEFAULT NULL COMMENT '创建人的用户id', `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', `update_by` bigint(0) NULL DEFAULT NULL COMMENT '更新人', `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', `del_flag` int(0) NULL DEFAULT 0 COMMENT '删除标志(0代表未删除,1代表已删除)', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_user -- ---------------------------- INSERT INTO `sys_user` VALUES (1, 'xbs', '小扳手', '$2a$10$WCD7xp6lxrS.PvGmL86nhuFHMKJTc58Sh0dG1EQw0zSHjlLFyFvde', '0', NULL, NULL, NULL, NULL, '1', NULL, NULL, NULL, NULL, 0); INSERT INTO `sys_user` VALUES (2, 'test', '测试用户', '$10$WCD7xp6lxrS.PvGmL86nhuFHMKJTc58Sh0dG1EQw0zSHjlLFyFvde', '0', NULL, NULL, NULL, NULL, '1', NULL, NULL, NULL, NULL, 0); -- ---------------------------- -- Table structure for sys_user_role -- ---------------------------- DROP TABLE IF EXISTS `sys_user_role`; CREATE TABLE `sys_user_role` ( `user_id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '用户id', `role_id` bigint(0) NOT NULL DEFAULT 0 COMMENT '角色id', PRIMARY KEY (`user_id`, `role_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_user_role -- ---------------------------- INSERT INTO `sys_user_role` VALUES (1, 1); INSERT INTO `sys_user_role` VALUES (2, 2);
2.0 Spring Security 核心功能-授权
2.1 思路分析
在登录验证过程中,即在实现 UserDetailsService 接口的 MyUserDetailService 实现类里面除了将用户的基本信息进行封装返回,还需要将用户的权限信息也要进行封装返回。
2.2 编写 SQL 语句
以用户 "xbs" 为例子:
当然可以直接通过多个表关联查询,这里将 SQL 分开是为了更好梳理用户、角色、权限之间的关系。
2.3 将用户权限进行封装
由于需要封装到 LoginUser 类中,则添加 List permissions 成员变量来存放权限信息,且为了其他类可以获取到这些权限信息,还需要重写 getAuthorities() 方法,返回权限信息。
@Data @NoArgsConstructor @AllArgsConstructor public class LoginUser implements UserDetails { /** 使用构造方法初始化 */ private User user; /** 存储权限信息 */ private List permissions; /** 存储SpringSecurity所需要的权限信息的集合 */ @JSONField(serialize = false) private List authorities; /** 重写getAuthorities方法,将String类型的权限List转换成GrantedAuthority类型的集合 */ @Override public Collection