主要更新: 1. 新增管理员权限检查功能 - 添加 UserRoleEnum 枚举类统一管理用户角色(USER, ADMIN, BAN) - 改进 ContextHolderUtils.isAdmin() 方法,支持不区分大小写的角色比较 - 更新 UserServiceImpl 使用枚举常量代替硬编码字符串 - 新增管理员权限使用指南文档 (docs/admin-permission-guide.md) 2. 修复Maven打包配置 - 配置根POM的spring-boot-maven-plugin默认跳过repackage - 为所有服务模块启用repackage,确保可以打包为可执行JAR - 修复公共库模块打包失败的问题 - 涉及服务:gateway, auth, user-service, question-service, file-service, blog-service, upms-biz, ai-service 3. 更新项目文档 - README.md:添加详细的打包说明、首次克隆准备工作、服务启动顺序等 - CLAUDE.md:更新项目架构说明和开发指南 4. 重构题目服务责任链结构 - 将责任链类按功能分类到 question/ 和 submit/ 子目录 - 新增 QuestionSubmitJudgeInfoEnum 和相关查询功能 - 改进题目提交服务的实现 5. 其他改进 - 添加 Feign Token 中继拦截器 - 更新 AsyncConfig 配置 - 优化 Jackson 和 Security 配置
6.8 KiB
6.8 KiB
管理员权限检查功能使用指南
功能位置
全局管理员权限检查功能已在 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. 检查当前用户是否为管理员
import cn.meowrain.aioj.backend.framework.core.utils.ContextHolderUtils;
// 在任何需要检查管理员权限的地方
if (ContextHolderUtils.isAdmin()) {
// 管理员才能执行的操作
log.info("当前用户是管理员");
} else {
// 非管理员的处理逻辑
throw new ClientException("无权限执行此操作");
}
2. 获取当前用户ID
// 获取当前登录用户ID(未登录会抛出异常)
Long userId = ContextHolderUtils.getCurrentUserId();
// 获取当前用户ID(未登录返回null)
Long userId = ContextHolderUtils.getCurrentUserIdOrNull();
3. 获取当前用户角色
// 获取当前用户角色字符串
String role = ContextHolderUtils.getCurrentUserRole();
// 使用枚举进行角色判断
if (UserRoleEnum.isAdmin(role)) {
// 管理员逻辑
}
4. 检查用户是否已登录
if (ContextHolderUtils.isAuthenticated()) {
// 用户已登录
}
在Controller中使用示例
示例1:限制删除操作仅管理员可用
@DeleteMapping("/{id}")
@Operation(summary = "删除题目")
public Result<Void> deleteQuestion(@PathVariable Long id) {
// 检查管理员权限
if (!ContextHolderUtils.isAdmin()) {
throw new ClientException("只有管理员才能删除题目");
}
questionService.deleteById(id);
return Result.success();
}
示例2:根据角色返回不同数据
@GetMapping("/list")
@Operation(summary = "获取题目列表")
public Result<List<QuestionDTO>> listQuestions() {
boolean isAdmin = ContextHolderUtils.isAdmin();
if (isAdmin) {
// 管理员可以看到所有题目(包括未发布的)
return Result.success(questionService.listAll());
} else {
// 普通用户只能看到已发布的题目
return Result.success(questionService.listPublished());
}
}
示例3:限制更新操作(仅作者或管理员)
@PutMapping("/{id}")
@Operation(summary = "更新题目")
public Result<Void> 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层使用示例
@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的注解:
import org.springframework.security.access.prepost.PreAuthorize;
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('admin')") // 注意:角色名会自动转换为小写
@Operation(summary = "删除题目")
public Result<Void> deleteQuestion(@PathVariable Long id) {
questionService.deleteById(id);
return Result.success();
}
注意:使用 @PreAuthorize 需要在配置类上启用方法级安全:
@Configuration
@EnableMethodSecurity // Spring Boot 3.x
public class SecurityConfig {
// ...
}
角色枚举使用
在需要设置或比较角色时,使用枚举常量:
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) {
// 管理员逻辑
}
注意事项
- 大小写不敏感:角色比较不区分大小写,"admin"、"Admin"、"ADMIN" 都会被识别为管理员
- 异常处理:
getCurrentUserId()和getCurrentUserRole()在用户未登录时会抛出IllegalStateException - 安全性:建议在Controller和Service层都进行权限检查,实现多层防护
- JWT依赖:此功能依赖JWT认证,确保请求头中包含有效的JWT token
完整示例:题目管理Controller
@RestController
@RequestMapping("/api/question")
@RequiredArgsConstructor
public class QuestionController {
private final QuestionService questionService;
@PostMapping
@Operation(summary = "创建题目(仅管理员)")
public Result<Long> 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<Void> 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<Void> deleteQuestion(@PathVariable Long id) {
if (!ContextHolderUtils.isAdmin()) {
throw new ClientException("只有管理员才能删除题目");
}
questionService.deleteById(id);
return Result.success();
}
@GetMapping("/{id}")
@Operation(summary = "获取题目详情")
public Result<QuestionDTO> getQuestion(@PathVariable Long id) {
// 普通用户和管理员都可以查看
QuestionDTO question = questionService.getById(id);
return Result.success(question);
}
}