本文目录导读:

我来为你提供一个完整的RBAC(基于角色的访问控制)案例,从需求分析到代码实现。
业务场景
假设我们要为一个企业管理系统设计RBAC权限模型,包含用户管理、项目管理、任务管理三个核心模块。
数据库设计
基础表结构
-- 用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
email VARCHAR(100),
status TINYINT DEFAULT 1 COMMENT '1:启用,0:禁用',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 角色表
CREATE TABLE roles (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(50) NOT NULL UNIQUE,
role_code VARCHAR(50) NOT NULL UNIQUE,
description VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 权限表
CREATE TABLE permissions (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
perm_name VARCHAR(50) NOT NULL,
perm_code VARCHAR(50) NOT NULL UNIQUE,
module VARCHAR(50) COMMENT '所属模块',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 用户-角色关联表
CREATE TABLE user_roles (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
UNIQUE KEY uk_user_role (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (role_id) REFERENCES roles(id)
);
-- 角色-权限关联表
CREATE TABLE role_permissions (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
role_id BIGINT NOT NULL,
permission_id BIGINT NOT NULL,
UNIQUE KEY uk_role_perm (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id),
FOREIGN KEY (permission_id) REFERENCES permissions(id)
);
初始化数据
-- 插入权限数据
INSERT INTO permissions (perm_name, perm_code, module) VALUES
-- 用户管理模块
('查询用户', 'user:list', 'user'),
('创建用户', 'user:create', 'user'),
('编辑用户', 'user:edit', 'user'),
('删除用户', 'user:delete', 'user'),
-- 项目管理模块
('查看项目', 'project:view', 'project'),
('创建项目', 'project:create', 'project'),
('编辑项目', 'project:edit', 'project'),
('删除项目', 'project:delete', 'project'),
-- 任务管理模块
('查看任务', 'task:view', 'task'),
('创建任务', 'task:create', 'task'),
('编辑任务', 'task:edit', 'task'),
('删除任务', 'task:delete', 'task'),
('分配任务', 'task:assign', 'task');
-- 插入角色数据
INSERT INTO roles (role_name, role_code, description) VALUES
('系统管理员', 'ADMIN', '拥有所有权限'),
('项目经理', 'PROJECT_MANAGER', '管理项目和任务'),
('开发人员', 'DEV', '处理任务'),
('访客', 'GUEST', '只读权限');
-- 分配角色权限
-- 管理员拥有所有权限
INSERT INTO role_permissions (role_id, permission_id)
SELECT 1, id FROM permissions;
-- 项目经理(查看项目、创建项目、编辑项目、删除项目、查看任务、创建任务、分配任务)
INSERT INTO role_permissions (role_id, permission_id) VALUES
(2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 10), (2, 13);
-- 开发人员(查看任务、编辑任务)
INSERT INTO role_permissions (role_id, permission_id) VALUES
(3, 9), (3, 11);
-- 访客(查看项目、查看任务)
INSERT INTO role_permissions (role_id, permission_id) VALUES
(4, 5), (4, 9);
Java代码实现
权限注解定义
package com.example.rbac.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresPermission {
String value();
}
核心实体类
package com.example.rbac.entity;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Set;
@Data
public class User {
private Long id;
private String username;
private String password;
private String email;
private Integer status;
private LocalDateTime createdAt;
private Set<Role> roles;
}
@Data
public class Role {
private Long id;
private String roleName;
private String roleCode;
private String description;
private Set<Permission> permissions;
}
@Data
public class Permission {
private Long id;
private String permName;
private String permCode;
private String module;
}
权限服务层
package com.example.rbac.service;
import com.example.rbac.entity.Permission;
import com.example.rbac.entity.Role;
import com.example.rbac.entity.User;
public interface PermissionService {
/**
* 获取用户所有权限
*/
Set<String> getUserPermissions(Long userId);
/**
* 验证用户是否拥有指定权限
*/
boolean hasPermission(Long userId, String permissionCode);
/**
* 获取用户角色列表
*/
Set<Role> getUserRoles(Long userId);
}
@Service
public class PermissionServiceImpl implements PermissionService {
@Autowired
private UserRoleMapper userRoleMapper;
@Autowired
private RolePermissionMapper rolePermissionMapper;
@Override
public Set<String> getUserPermissions(Long userId) {
// 使用缓存提升性能
String cacheKey = "user:permissions:" + userId;
Set<String> permissions = redisUtil.get(cacheKey);
if (permissions == null) {
// 查询用户角色
List<Role> roles = userRoleMapper.findRolesByUserId(userId);
// 通过角色获取权限
Set<String> permCodes = new HashSet<>();
for (Role role : roles) {
List<Permission> permissions = rolePermissionMapper.findPermissionsByRoleId(role.getId());
permissions.forEach(perm -> permCodes.add(perm.getPermCode()));
}
permissions = permCodes;
// 缓存10分钟
redisUtil.set(cacheKey, permissions, 600);
}
return permissions;
}
@Override
public boolean hasPermission(Long userId, String permissionCode) {
Set<String> permissions = getUserPermissions(userId);
return permissions.contains(permissionCode);
}
}
自定义权限拦截器
package com.example.rbac.interceptor;
import com.example.rbac.annotation.RequiresPermission;
import com.example.rbac.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class PermissionInterceptor implements HandlerInterceptor {
@Autowired
private PermissionService permissionService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 如果不是映射到方法,直接通过
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
RequiresPermission requiresPermission = handlerMethod.getMethodAnnotation(RequiresPermission.class);
if (requiresPermission == null) {
return true;
}
// 获取当前登录用户ID(这里假设从Session中获取)
Long userId = (Long) request.getSession().getAttribute("userId");
if (userId == null) {
response.setStatus(401);
return false;
}
// 验证权限
if (!permissionService.hasPermission(userId, requiresPermission.value())) {
response.setStatus(403);
response.setContentType("application/json");
response.getWriter().write("{\"code\":403,\"message\":\"权限不足\"}");
return false;
}
return true;
}
}
控制器示例
package com.example.rbac.controller;
import com.example.rbac.annotation.RequiresPermission;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/projects")
public class ProjectController {
@GetMapping
@RequiresPermission("project:view")
public Result listProjects() {
// 查看项目列表
return Result.success();
}
@PostMapping
@RequiresPermission("project:create")
public Result createProject(@RequestBody ProjectDTO projectDTO) {
// 创建项目
return Result.success();
}
@PutMapping("/{id}")
@RequiresPermission("project:edit")
public Result editProject(@PathVariable Long id, @RequestBody ProjectDTO projectDTO) {
// 编辑项目
return Result.success();
}
@DeleteMapping("/{id}")
@RequiresPermission("project:delete")
public Result deleteProject(@PathVariable Long id) {
// 删除项目
return Result.success();
}
}
动态菜单和按钮控制
package com.example.rbac.controller;
@RestController
@RequestMapping("/api/menu")
public class MenuController {
@Autowired
private PermissionService permissionService;
@GetMapping("/user")
public Result getUserMenus(Long userId) {
// 获取用户所有权限码
Set<String> permissions = permissionService.getUserPermissions(userId);
// 构建菜单树
List<MenuVO> menus = new ArrayList<>();
// 根据权限动态生成菜单
if (permissions.contains("user:list")) {
menus.add(new MenuVO("用户管理", "/user/list", "user"));
}
if (permissions.contains("project:view")) {
menus.add(new MenuVO("项目管理", "/project/list", "project"));
}
if (permissions.contains("task:view")) {
menus.add(new MenuVO("任务管理", "/task/list", "task"));
}
return Result.success(menus);
}
}
MyBatis Mapper示例
@Mapper
public interface UserRoleMapper {
@Select("SELECT r.* FROM roles r " +
"INNER JOIN user_roles ur ON r.id = ur.role_id " +
"WHERE ur.user_id = #{userId}")
List<Role> findRolesByUserId(Long userId);
@Insert("INSERT INTO user_roles (user_id, role_id) VALUES (#{userId}, #{roleId})")
int insertUserRole(@Param("userId") Long userId, @Param("roleId") Long roleId);
@Delete("DELETE FROM user_roles WHERE user_id = #{userId} AND role_id = #{roleId}")
int deleteUserRole(@Param("userId") Long userId, @Param("roleId") Long roleId);
}
@Mapper
public interface RolePermissionMapper {
@Select("SELECT p.* FROM permissions p " +
"INNER JOIN role_permissions rp ON p.id = rp.permission_id " +
"WHERE rp.role_id = #{roleId}")
List<Permission> findPermissionsByRoleId(Long roleId);
@Insert("INSERT INTO role_permissions (role_id, permission_id) VALUES (#{roleId}, #{permissionId})")
int insertRolePermission(@Param("roleId") Long roleId, @Param("permissionId") Long permissionId);
@Delete("DELETE FROM role_permissions WHERE role_id = #{roleId}")
int deleteRolePermissions(Long roleId);
}
前端按钮权限控制
// 权限指令定义
Vue.directive('permission', {
bind(el, binding) {
const requiredPermission = binding.value;
const userPermissions = store.state.userPermissions || [];
if (!userPermissions.includes(requiredPermission)) {
el.parentNode.removeChild(el);
}
}
});
// 按钮控制示例
<el-button
v-permission="'project:delete'"
type="danger"
@click="deleteProject">
删除项目
</el-button>
<el-button
v-if="checkPermission('task:assign')"
type="primary">
分配任务
</el-button>
测试用例
@SpringBootTest
public class RbacTest {
@Autowired
private PermissionService permissionService;
@Test
public void testAdminPermissions() {
// 假设用户1是管理员
assertTrue(permissionService.hasPermission(1L, "user:create"));
assertTrue(permissionService.hasPermission(1L, "project:delete"));
assertTrue(permissionService.hasPermission(1L, "task:assign"));
}
@Test
public void testDevPermissions() {
// 假设用户3是开发人员
assertTrue(permissionService.hasPermission(3L, "task:view"));
assertTrue(permissionService.hasPermission(3L, "task:edit"));
assertFalse(permissionService.hasPermission(3L, "project:delete"));
}
@Test
public void testGuestPermissions() {
// 假设用户4是访客
assertTrue(permissionService.hasPermission(4L, "project:view"));
assertTrue(permissionService.hasPermission(4L, "task:view"));
assertFalse(permissionService.hasPermission(4L, "task:edit"));
assertFalse(permissionService.hasPermission(4L, "user:create"));
}
}
性能优化建议
// 1. 使用Redis缓存权限信息
public void clearPermissionCache(Long userId) {
String cacheKey = "user:permissions:" + userId;
redisUtil.delete(cacheKey);
}
// 2. 权限变更时清除缓存
@Transactional
public void updateRolePermissions(Long roleId, List<Long> permissionIds) {
rolePermissionMapper.deleteRolePermissions(roleId);
for (Long permissionId : permissionIds) {
rolePermissionMapper.insertRolePermission(roleId, permissionId);
}
// 清除受影响用户的缓存
List<Long> userIds = userMapper.findUsersByRoleId(roleId);
userIds.forEach(this::clearPermissionCache);
}
// 3. 使用布隆过滤器快速过滤无权限请求
@Component
public class PermissionBloomFilter {
private final BloomFilter<String> filter = BloomFilter.create(
Funnels.stringFunnel(StandardCharsets.UTF_8), 100000, 0.01);
public boolean mightContain(String permCode) {
return filter.mightContain(permCode);
}
@Scheduled(initialDelay = 60000, fixedDelay = 86400000)
public void refresh() {
List<String> allPermCodes = permissionMapper.findAllPermCodes();
allPermCodes.forEach(filter::put);
}
}
这个RBAC案例涵盖了:
- 完整的数据库设计:用户、角色、权限三类核心表及关联表
- 灵活的权限控制:支持注解和动态API级别的权限校验
- 前端配合:按钮级别和菜单级别的权限控制
- 性能优化:基于Redis的缓存机制
- 完整的测试覆盖:针对不同角色的权限验证
RBAC模型的核心优势是松耦合和易于扩展,新增角色只需要配置权限组合,不需要修改业务代码。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播