springcloud:理解springsecurity安全架构与认证链路(二)RBAC 权限模型与数据库设计
在电商系统中,认证只告诉我们“你是谁”,而授权决定了“你能做什么”。RBAC(Role-Based Access Control,基于角色的访问控制)是企业级系统最常用的权限管理模型。
在微服务场景中,RBAC 不仅要支持接口权限,还要支持页面/按钮级权限,还需要动态加载和缓存。
1)为什么要用 RBAC
-
是什么:RBAC 是一种基于角色的权限控制模型,把权限绑定到角色,用户绑定到角色。
-
在干什么:实现“用户 → 角色 → 权限”的映射关系,使权限管理可维护、可扩展、可审计。
-
为什么要这么做:电商平台用户类型多(买家、卖家、运营、管理员),直接把权限赋给用户会非常混乱。
-
不这么做会怎样:权限随业务复杂度爆炸,修改用户权限困难,审计难度大,容易出安全漏洞。
-
注意点:
- 角色应抽象业务场景,而不是只映射到单个用户。
- 权限粒度要够细(接口、页面、按钮、字段)。
- 支持动态加载,权限修改后无需重启系统。
2)RBAC 数据库表设计(电商场景示例)
我们基于电商常见操作(订单管理、商品管理、用户管理、促销管理)设计数据库表。
A. 用户表(user)
CREATE TABLE `user` (`id` BIGINT PRIMARY KEY AUTO_INCREMENT,`username` VARCHAR(50) NOT NULL UNIQUE,`password` VARCHAR(100) NOT NULL,`status` TINYINT DEFAULT 1 COMMENT '1-正常,0-禁用',`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
存储电商系统登录账号信息。密码建议使用 bcrypt 加密。
B. 角色表(role)
CREATE TABLE `role` (`id` BIGINT PRIMARY KEY AUTO_INCREMENT,`name` VARCHAR(50) NOT NULL UNIQUE COMMENT '角色名称',`description` VARCHAR(255) COMMENT '角色描述',`status` TINYINT DEFAULT 1 COMMENT '1-正常,0-禁用'
);
例如:
BUYER,SELLER,ADMIN,OPERATOR。
C. 权限表(permission)
CREATE TABLE `permission` (`id` BIGINT PRIMARY KEY AUTO_INCREMENT,`name` VARCHAR(100) NOT NULL UNIQUE COMMENT '权限标识',`type` VARCHAR(20) NOT NULL COMMENT '接口/菜单/按钮',`url` VARCHAR(255) COMMENT '接口路径或菜单地址',`method` VARCHAR(10) DEFAULT 'GET' COMMENT 'HTTP 方法',`description` VARCHAR(255),`status` TINYINT DEFAULT 1 COMMENT '1-正常,0-禁用'
);
权限粒度:接口、菜单、按钮。
例如:order:create(创建订单接口)、product:edit(商品编辑按钮)、user:view(用户列表页面)。
D. 用户-角色表(user_role)
CREATE TABLE `user_role` (`user_id` BIGINT NOT NULL,`role_id` BIGINT NOT NULL,PRIMARY KEY (`user_id`,`role_id`),FOREIGN KEY (`user_id`) REFERENCES `user`(`id`),FOREIGN KEY (`role_id`) REFERENCES `role`(`id`)
);
用户绑定角色,一个用户可以有多个角色。
E. 角色-权限表(role_permission)
CREATE TABLE `role_permission` (`role_id` BIGINT NOT NULL,`permission_id` BIGINT NOT NULL,PRIMARY KEY (`role_id`,`permission_id`),FOREIGN KEY (`role_id`) REFERENCES `role`(`id`),FOREIGN KEY (`permission_id`) REFERENCES `permission`(`id`)
);
角色绑定权限,一个角色可以有多个权限。
F. 示例数据(电商场景)
-- 用户
INSERT INTO user(username, password) VALUES ('alice', 'bcrypt_pwd'),('bob', 'bcrypt_pwd');-- 角色
INSERT INTO role(name, description) VALUES ('BUYER','买家'),('SELLER','卖家'),('ADMIN','管理员');-- 权限
INSERT INTO permission(name,type,url,method) VALUES
('order:create','API','/order/create','POST'),
('order:view','API','/order/list','GET'),
('product:edit','BUTTON','/product/edit','POST'),
('user:view','MENU','/user/list','GET');-- 用户角色绑定
INSERT INTO user_role(user_id, role_id) VALUES (1,1),(2,2),(2,3);-- 角色权限绑定
INSERT INTO role_permission(role_id, permission_id) VALUES
(1,1),(1,2),(2,2),(2,3),(3,1),(3,2),(3,3),(3,4);
3)Spring Security 加载 RBAC 权限
在微服务中,我们通过 UserDetailsService + JWT 把 RBAC 权限加载到认证系统里。
@Service
public class CustomUserDetailsService implements UserDetailsService {@Autowiredprivate UserRepository userRepository;@Autowiredprivate RoleRepository roleRepository;@Autowiredprivate PermissionRepository permissionRepository;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userRepository.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User not found"));// 加载角色List<Role> roles = roleRepository.findByUserId(user.getId());// 加载权限List<Permission> permissions = permissionRepository.findByRoleIds(roles.stream().map(Role::getId).toList());// 转换为 Spring Security 的 GrantedAuthoritySet<GrantedAuthority> authorities = permissions.stream().map(p -> new SimpleGrantedAuthority(p.getName())).collect(Collectors.toSet());return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);}
}
核心思路:
- 用户登录 → 查询用户表
- 查询角色 → 查询权限
- 构建 GrantedAuthority → JWT 生成 token 或 Spring Security 上下文存储
4)优化与注意点
-
缓存权限
- 每次请求查询 DB 会增加压力,可将角色-权限关系缓存到 Redis 或内存。
-
动态刷新
- RBAC 权限修改后,需让缓存失效或动态更新,保证实时生效。
-
权限粒度
- API + 菜单 + 按钮级别,便于前端动态渲染界面。
-
多服务共享
- 微服务可共享认证中心 / RBAC 表结构,或通过接口同步权限信息。
5)本文小结
- 本篇详细介绍了 RBAC 表结构设计、示例数据以及如何在 Spring Security 中加载和使用权限。
- 我们下一篇将实现 OAuth2 认证中心(登录、Token 签发、刷新),把 RBAC 与 JWT 完整串联起来,实现真正的电商微服务安全认证链路。
