角色权限控制RBAC与动态菜单实验目的1.理解 RBAC基于角色的访问控制模型。2.掌握用户-角色-权限的关系设计。3.掌握基于 JWT 的权限控制实现方式。4.实现接口权限校验不同角色访问不同接口。5.实现动态菜单根据权限返回菜单数据。实验环境开发工具IntelliJ IDEA构建工具Maven测试工具Postman或浏览器AI工具通义灵码实验要求在校园二手交易系统中实现权限控制功能1.实现用户、角色、权限三张核心表2.登录后返回用户角色信息3.不同角色访问不同接口4.实现动态菜单接口按权限返回5.未授权访问返回错误信息实验内容第一部分RBAC模型设计RBAC 核心关系用户User → 角色Role → 权限Permission关系说明一个用户可以有多个角色一个角色可以有多个权限权限决定可以访问哪些接口第二部分数据库设计1.用户表CREATE TABLE user (id BIGINT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(50),password VARCHAR(100));2.角色表roleCREATE TABLE role (id BIGINT PRIMARY KEY AUTO_INCREMENT,role_name VARCHAR(50));3.权限表permissionCREATE TABLE permission (id BIGINT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50),path VARCHAR(100));4.用户角色表user_roleCREATE TABLE user_role (user_id BIGINT,role_id BIGINT);5.角色权限表role_permissionCREATE TABLE role_permission (role_id BIGINT,permission_id BIGINT);6.示例数据-- 用户INSERT INTO user VALUES (1,jack,123456);INSERT INTO user VALUES (2,lily,123456);-- 角色INSERT INTO role VALUES (1,admin),(2,user);-- 权限INSERT INTO permission VALUES(1,查询商品,/goods/list),(2,添加商品,/goods/add);-- 用户角色INSERT INTO user_role VALUES (1,1);INSERT INTO user_role VALUES (2,2);-- 角色权限INSERT INTO role_permission VALUES (1,1),(1,2);INSERT INTO role_permission VALUES (2,1);第三部分创建Mapper接口创建UserMapperMapperpublic interface UserMapper extends BaseMapperUser {}2.创建RoleMapperMapperpublic interface RoleMapper extends BaseMapperRole {}3.创建PermissionMapperMapperpublic interface PermissionMapper extends BaseMapperPermission {}4.创建UserRoleMapperMapperpublic interface PermissionMapper extends BaseMapperPermission {}5.创建RolePermissionMapperMapperpublic interface PermissionMapper extends BaseMapperPermission {}第四部分创建DTO创建MenuDTODataBuilderNoArgsConstructorAllArgsConstructorpublic class MenuDTO {private String name;private String path;private String permission;}创建UserInfoDTODataBuilderNoArgsConstructorAllArgsConstructorpublic class UserInfoDTO {private Long userId;private String username;private ListString roles;private ListMenuDTO menus;}第五部分创建Service层1.创建PermissionServiceServicepublic class PermissionService {Autowiredprivate UserRoleMapper userRoleMapper;Autowiredprivate RoleMapper roleMapper;Autowiredprivate RolePermissionMapper rolePermissionMapper;Autowiredprivate PermissionMapper permissionMapper;public ListString getUserRoles(Long userId) {LambdaQueryWrapperUserRole wrapper new LambdaQueryWrapper();wrapper.eq(UserRole::getUserId, userId);ListUserRole userRoles userRoleMapper.selectList(wrapper);ListLong roleIds userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList());if (roleIds.isEmpty()) {return new ArrayList();}ListRole roles roleMapper.selectBatchIds(roleIds);return roles.stream().map(Role::getRoleName).collect(Collectors.toList());}public ListMenuDTO getUserMenus(Long userId) {ListString roles getUserRoles(userId);if (roles.isEmpty()) {return new ArrayList();}LambdaQueryWrapperRole roleWrapper new LambdaQueryWrapper();roleWrapper.in(Role::getRoleName, roles);ListRole roleList roleMapper.selectList(roleWrapper);ListLong roleIds roleList.stream().map(Role::getId).collect(Collectors.toList());LambdaQueryWrapperRolePermission rpWrapper new LambdaQueryWrapper();rpWrapper.in(RolePermission::getRoleId, roleIds);ListRolePermission rolePermissions rolePermissionMapper.selectList(rpWrapper);ListLong permissionIds rolePermissions.stream().map(RolePermission::getPermissionId).distinct().collect(Collectors.toList());if (permissionIds.isEmpty()) {return new ArrayList();}ListPermission permissions permissionMapper.selectBatchIds(permissionIds);return permissions.stream().map(p - MenuDTO.builder().name(p.getName()).path(p.getPath()).permission(p.getName()).build()).collect(Collectors.toList());}public boolean hasPermission(Long userId, String permissionName) {ListMenuDTO menus getUserMenus(userId);return menus.stream().anyMatch(menu - menu.getPermission().equals(permissionName));}}2.创建RoleServiceServicepublic class RoleService {Autowiredprivate RoleMapper roleMapper;Autowiredprivate UserRoleMapper userRoleMapper;Autowiredprivate RolePermissionMapper rolePermissionMapper;public Long getRoleIdByName(String roleName) {LambdaQueryWrapperRole wrapper new LambdaQueryWrapper();wrapper.eq(Role::getRoleName, roleName);Role role roleMapper.selectOne(wrapper);return role ! null ? role.getId() : null;}Transactionalpublic void assignRoleToUser(Long userId, Long roleId) {LambdaQueryWrapperUserRole wrapper new LambdaQueryWrapper();wrapper.eq(UserRole::getUserId, userId);userRoleMapper.delete(wrapper);UserRole userRole new UserRole();userRole.setUserId(userId);userRole.setRoleId(roleId);userRoleMapper.insert(userRole);}Transactionalpublic void assignPermissionToRole(Long roleId, Long permissionId) {LambdaQueryWrapperRolePermission wrapper new LambdaQueryWrapper();wrapper.eq(RolePermission::getRoleId, roleId).eq(RolePermission::getPermissionId, permissionId);if (rolePermissionMapper.selectCount(wrapper) 0) {RolePermission rolePermission new RolePermission();rolePermission.setRoleId(roleId);rolePermission.setPermissionId(permissionId);rolePermissionMapper.insert(rolePermission);}}}创建权限注解第六部分创建权限拦截器PermissionInterceptorComponentpublic class PermissionInterceptor implements HandlerInterceptor {Autowiredprivate JwtUtil jwtUtil;Autowiredprivate PermissionService permissionService;Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {if (!(handler instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod (HandlerMethod) handler;RequirePermission requirePermission handlerMethod.getMethodAnnotation(RequirePermission.class);if (requirePermission null) {requirePermission handlerMethod.getBeanType().getAnnotation(RequirePermission.class);}if (requirePermission ! null) {String token request.getHeader(Authorization);if (token ! null token.startsWith(Bearer )) {token token.substring(7);}Long userId jwtUtil.getUserIdFromToken(token);String permission requirePermission.value();if (!permissionService.hasPermission(userId, permission)) {throw new BusinessException(403, 没有权限访问此资源);}}return true;}}注册该拦截器registry.addInterceptor(permissionInterceptor).addPathPatterns(/**).excludePathPatterns(/auth/login, /auth/register);第七部分创建权限管理 PermissionControllerRestControllerRequestMapping(/permission)public class PermissionController {Autowiredprivate PermissionService permissionService;Autowiredprivate RoleService roleService;Autowiredprivate JwtUtil jwtUtil;GetMapping(/menus)public ResultListMenuDTO getUserMenus(HttpServletRequest request) {String token (String) request.getAttribute(token);Long userId jwtUtil.getUserIdFromToken(token);ListMenuDTO menus permissionService.getUserMenus(userId);return Result.success(menus);}GetMapping(/userinfo)public ResultUserInfoDTO getUserInfo(HttpServletRequest request) {String token (String) request.getAttribute(token);Long userId jwtUtil.getUserIdFromToken(token);String username jwtUtil.getUsernameFromToken(token);ListString roles permissionService.getUserRoles(userId);ListMenuDTO menus permissionService.getUserMenus(userId);UserInfoDTO userInfo UserInfoDTO.builder().userId(userId).username(username).roles(roles).menus(menus).build();return Result.success(userInfo);}PostMapping(/assign-role)public ResultString assignRole(RequestParam Long userId, RequestParam Long roleId) {roleService.assignRoleToUser(userId, roleId);return Result.success(角色分配成功);}PostMapping(/assign-permission)public ResultString assignPermission(RequestParam Long roleId, RequestParam Long permissionId) {roleService.assignPermissionToRole(roleId, permissionId);return Result.success(权限分配成功);}}第八部分测试功能1. 登录获取 token使用你数据库中的用户POST http://localhost:8080/auth/login{username: 你的用户名,password: 你的密码}2. 获取动态菜单GET http://localhost:8080/permission/menusAuthorization: Bearer {token}3. 获取用户信息含角色和权限GET http://localhost:8080/permission/userinfoAuthorization: Bearer {token}4. 测试权限控制GET http://localhost:8080/goods/list # 需要查看商品权限POST http://localhost:8080/goods/add # 需要商品管理权限