电商后台权限设计:RBAC模型从数据库到Spring Security的完整实现
电商后台的权限管理远不止"管理员能看到所有菜单,运营只能看订单"—还要细到"北京门店的运营只能看到北京地区的订单"、"A部门的员工不能操作B部门的商品"。这就是RBAC(基于角色的访问控制)加上数据权限隔离要解决的问题。
一、RBAC五张表的标准设计
标准的RBAC模型至少需要五张表:
-- 用户表
CREATE TABLE sys_user (
id BIGINT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
dept_id BIGINT,
status TINYINT DEFAULT 1
);
-- 角色表
CREATE TABLE sys_role (
id BIGINT PRIMARY KEY,
role_name VARCHAR(50) NOT NULL,
role_code VARCHAR(50) NOT NULL UNIQUE,
data_scope TINYINT DEFAULT 1 -- 1:全部 2:本部门 3:本部门及以下 4:仅本人
);
-- 权限表(菜单+按钮)
CREATE TABLE sys_permission (
id BIGINT PRIMARY KEY,
parent_id BIGINT DEFAULT 0,
perm_name VARCHAR(50) NOT NULL,
perm_type TINYINT NOT NULL -- 1:菜单 2:按钮
);
-- 用户-角色关联表
CREATE TABLE sys_user_role (
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
PRIMARY KEY (user_id, role_id)
);
-- 角色-权限关联表
CREATE TABLE sys_role_permission (
role_id BIGINT NOT NULL,
perm_id BIGINT NOT NULL,
PRIMARY KEY (role_id, perm_id)
);
这张表结构覆盖了90%的电商后台权限场景。data_scope字段是数据权限的关键——它决定了拥有该角色的用户能看到哪些数据范围。
二、Spring Security + JWT动态权限
Spring Security默认的hasRole('ADMIN')注解是硬编码的,角色一变就要改代码重新部署。动态权限的实现思路是:自定义FilterSecurityInterceptor,在每次请求时从数据库加载当前用户的权限列表,与请求URL匹配。
@Component
public class DynamicPermissionFilter extends OncePerRequestFilter {
@Autowired
private PermissionService permissionService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) {
// 1. 从JWT中解析userId
Long userId = JwtUtil.getUserIdFromToken(request);
// 2. 从Redis/DB获取该用户的权限列表
Set<String> permissions = permissionService.getPermissionsByUserId(userId);
// 3. 匹配当前请求URL
String requestURI = request.getRequestURI();
boolean hasPermission = permissions.stream()
.anyMatch(p -> pathMatcher.match(p, requestURI));
if (!hasPermission) {
response.setStatus(403);
return;
}
chain.doFilter(request, response);
}
}
权限列表建议缓存到Redis,设置合理的过期时间(如30分钟),避免每次请求都查数据库。权限变更时主动清除Redis缓存。
三、数据权限:部门隔离的实现
菜单权限控制"能不能看到这个页面",数据权限控制"在这个页面能看到哪些数据"。典型场景是:区域经理只能看到自己负责区域的订单和用户。
实现方式是在SQL查询层注入数据权限条件。自定义MyBatis拦截器或使用MyBatis-Plus的数据权限插件:
// 在SQL执行前,根据当前用户的数据权限范围追加WHERE条件
// 查询所有订单 → 自动变为 查询本部门+下级部门的订单
SELECT * FROM t_order WHERE dept_id IN (101, 102, 103)
数据权限的粒度设计需要和业务对齐:全部数据 > 本部门及下级 > 本部门 > 仅本人。不要追求过度的灵活性,四个级别足够覆盖99%的场景。
四、按钮级权限
菜单权限是粗粒度的,按钮权限是细粒度的。比如"订单列表"页面中,普通运营有"查看"按钮但没有"退款"按钮。前端用v-if根据权限列表控制按钮显示,后端在接口层再次校验——前端隐藏只是优化用户体验,真正的安全防线在后端。
五、前端路由的动态加载
Vue Router的addRoutes可以根据后端返回的菜单树动态注册路由。用户登录后,前端请求/api/user/menus接口,拿到该用户有权限的菜单列表,动态构建路由表。这样即使用户在浏览器地址栏输入了未授权的URL,路由表中不存在对应路由,自然跳转到404。
在搭建权限体系时,参考一些成熟的开源项目(如CRMEB中的RBAC实现)可以节省大量从零设计的时间。CRMEB的数据权限隔离方案中,SQL拦截器的设计尤其值得细读。
SEO小贴士
核心关键词:Java商城权限设计、Spring Security RBAC、电商后台权限、数据权限隔离
长尾词:JWT动态权限、MyBatis数据权限插件、按钮级权限控制、Vue动态路由权限
内容策略:从数据库设计到前后端实现全链路覆盖,搜索"RBAC"的用户通常需要完整方案
结构化优势:SQL建表语句 + Java代码 + 前端方案三位一体,搜索引擎更容易识别为高质量技术内容
更多推荐



所有评论(0)