# 管理员权限检查功能使用指南 ## 功能位置 全局管理员权限检查功能已在 `aioj-backend-common-core` 模块中实现,所有服务模块都可以直接使用。 ## 核心类 ### 1. UserRoleEnum(角色枚举) **位置**: `cn.meowrain.aioj.backend.framework.core.enums.UserRoleEnum` 定义了系统中的所有用户角色: - `USER` - 普通用户(code: "user") - `ADMIN` - 管理员(code: "admin") - `BAN` - 封禁用户(code: "ban") ### 2. ContextHolderUtils(上下文工具类) **位置**: `cn.meowrain.aioj.backend.framework.core.utils.ContextHolderUtils` 提供了获取当前登录用户信息的工具方法。 ## 使用方法 ### 1. 检查当前用户是否为管理员 ```java import cn.meowrain.aioj.backend.framework.core.utils.ContextHolderUtils; // 在任何需要检查管理员权限的地方 if (ContextHolderUtils.isAdmin()) { // 管理员才能执行的操作 log.info("当前用户是管理员"); } else { // 非管理员的处理逻辑 throw new ClientException("无权限执行此操作"); } ``` ### 2. 获取当前用户ID ```java // 获取当前登录用户ID(未登录会抛出异常) Long userId = ContextHolderUtils.getCurrentUserId(); // 获取当前用户ID(未登录返回null) Long userId = ContextHolderUtils.getCurrentUserIdOrNull(); ``` ### 3. 获取当前用户角色 ```java // 获取当前用户角色字符串 String role = ContextHolderUtils.getCurrentUserRole(); // 使用枚举进行角色判断 if (UserRoleEnum.isAdmin(role)) { // 管理员逻辑 } ``` ### 4. 检查用户是否已登录 ```java if (ContextHolderUtils.isAuthenticated()) { // 用户已登录 } ``` ## 在Controller中使用示例 ### 示例1:限制删除操作仅管理员可用 ```java @DeleteMapping("/{id}") @Operation(summary = "删除题目") public Result deleteQuestion(@PathVariable Long id) { // 检查管理员权限 if (!ContextHolderUtils.isAdmin()) { throw new ClientException("只有管理员才能删除题目"); } questionService.deleteById(id); return Result.success(); } ``` ### 示例2:根据角色返回不同数据 ```java @GetMapping("/list") @Operation(summary = "获取题目列表") public Result> listQuestions() { boolean isAdmin = ContextHolderUtils.isAdmin(); if (isAdmin) { // 管理员可以看到所有题目(包括未发布的) return Result.success(questionService.listAll()); } else { // 普通用户只能看到已发布的题目 return Result.success(questionService.listPublished()); } } ``` ### 示例3:限制更新操作(仅作者或管理员) ```java @PutMapping("/{id}") @Operation(summary = "更新题目") public Result updateQuestion( @PathVariable Long id, @RequestBody QuestionUpdateDTO request) { Question question = questionService.getById(id); Long currentUserId = ContextHolderUtils.getCurrentUserId(); boolean isAdmin = ContextHolderUtils.isAdmin(); // 只有题目创建者或管理员可以更新 if (!isAdmin && !question.getCreatorId().equals(currentUserId)) { throw new ClientException("无权限修改此题目"); } questionService.updateQuestion(id, request); return Result.success(); } ``` ## 在Service层使用示例 ```java @Service public class QuestionServiceImpl implements QuestionService { @Override public void deleteQuestion(Long id) { // 在Service层也可以进行权限检查 if (!ContextHolderUtils.isAdmin()) { throw new ServiceException("权限不足"); } // 执行删除逻辑 this.removeById(id); } } ``` ## 使用Spring Security注解(推荐) 除了手动检查,还可以使用Spring Security的注解: ```java import org.springframework.security.access.prepost.PreAuthorize; @DeleteMapping("/{id}") @PreAuthorize("hasRole('admin')") // 注意:角色名会自动转换为小写 @Operation(summary = "删除题目") public Result deleteQuestion(@PathVariable Long id) { questionService.deleteById(id); return Result.success(); } ``` **注意**:使用 `@PreAuthorize` 需要在配置类上启用方法级安全: ```java @Configuration @EnableMethodSecurity // Spring Boot 3.x public class SecurityConfig { // ... } ``` ## 角色枚举使用 在需要设置或比较角色时,使用枚举常量: ```java import cn.meowrain.aioj.backend.framework.core.enums.UserRoleEnum; // 设置用户角色 user.setUserRole(UserRoleEnum.ADMIN.getCode()); // 判断角色 if (UserRoleEnum.isAdmin(user.getUserRole())) { // 管理员逻辑 } // 根据代码获取枚举 UserRoleEnum role = UserRoleEnum.fromCode("admin"); if (role == UserRoleEnum.ADMIN) { // 管理员逻辑 } ``` ## 注意事项 1. **大小写不敏感**:角色比较不区分大小写,"admin"、"Admin"、"ADMIN" 都会被识别为管理员 2. **异常处理**:`getCurrentUserId()` 和 `getCurrentUserRole()` 在用户未登录时会抛出 `IllegalStateException` 3. **安全性**:建议在Controller和Service层都进行权限检查,实现多层防护 4. **JWT依赖**:此功能依赖JWT认证,确保请求头中包含有效的JWT token ## 完整示例:题目管理Controller ```java @RestController @RequestMapping("/api/question") @RequiredArgsConstructor public class QuestionController { private final QuestionService questionService; @PostMapping @Operation(summary = "创建题目(仅管理员)") public Result createQuestion(@RequestBody QuestionCreateDTO request) { if (!ContextHolderUtils.isAdmin()) { throw new ClientException("只有管理员才能创建题目"); } Long questionId = questionService.create(request); return Result.success(questionId); } @PutMapping("/{id}") @Operation(summary = "更新题目(仅管理员)") public Result updateQuestion( @PathVariable Long id, @RequestBody QuestionUpdateDTO request) { if (!ContextHolderUtils.isAdmin()) { throw new ClientException("只有管理员才能更新题目"); } questionService.update(id, request); return Result.success(); } @DeleteMapping("/{id}") @Operation(summary = "删除题目(仅管理员)") public Result deleteQuestion(@PathVariable Long id) { if (!ContextHolderUtils.isAdmin()) { throw new ClientException("只有管理员才能删除题目"); } questionService.deleteById(id); return Result.success(); } @GetMapping("/{id}") @Operation(summary = "获取题目详情") public Result getQuestion(@PathVariable Long id) { // 普通用户和管理员都可以查看 QuestionDTO question = questionService.getById(id); return Result.success(question); } } ```