refactor(admin): 重构管理模块VO包结构并新增标签管理功能

- 将分类相关VO移至com.hanserwei.admin.model.vo.category包下,用户相关VO移至user包
- 新增标签管理相关VO,包括AddTagReqVO、DeleteTagReqVO、FindTagPageListReqVO、FindTagPageListRspVO、SearchTagReqVO
- 增加AdminTagController,实现标签的增删查和分页查询接口
- 实现AdminTagService及其Impl,完成标签的增删查分页功能
- 新增Tag实体及TagRepository,支持标签数据的持久化及模糊查询
- 优化AdminCategoryServiceImpl分页查询逻辑,提取公共分页查询工具类PageHelper
- 修改CategoryRepository继承JpaSpecificationExecutor,支持动态查询
- 修改TokenAuthenticationFilter,限制JWT认证仅校验/admin路径请求
- 修改Category实体删除注解,调整逻辑删除实现
- 新增数据库脚本,创建t_tag标签表及相关索引和触发器
- 更新ResponseCodeEnum,增加TAG_NOT_EXIST和CATEGORY_NOT_EXIST错误码
- 调整.gitignore,忽略.idea下Apifox相关缓存文件
This commit is contained in:
2025-12-04 23:18:10 +08:00
parent b7afe9496a
commit 304c458436
29 changed files with 641 additions and 127 deletions

View File

@@ -44,58 +44,64 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
// 1. 从请求头中获取 Authorization
String header = request.getHeader("Authorization");
// 2. 校验头格式 (必须以 Bearer 开头)
if (header != null && header.startsWith("Bearer ")) {
String token = StringUtils.substring(header, 7);
log.info("JWT Token: {}", token);
if (StringUtils.isNotBlank(token)) {
try {
// 3. 解析 Token (核心步骤)
// 注意JwtTokenHelper.parseToken 方法内部已经处理了 JWT 格式校验和过期校验,
// 并将 JJWT 异常转换为了 Spring Security 的 AuthenticationException 抛出。
Jws<Claims> claimsJws = jwtTokenHelper.parseToken(token);
String requestURI = request.getRequestURI();
log.info("Request URI: {}", requestURI);
if (requestURI.startsWith("/admin")) {
// 2. 校验头格式 (必须以 Bearer 开头)
if (header != null && header.startsWith("Bearer ")) {
String token = StringUtils.substring(header, 7);
log.info("JWT Token: {}", token);
if (StringUtils.isNotBlank(token)) {
try {
// 3. 解析 Token (核心步骤)
// 注意JwtTokenHelper.parseToken 方法内部已经处理了 JWT 格式校验和过期校验,
// 并将 JJWT 异常转换为了 Spring Security 的 AuthenticationException 抛出。
Jws<Claims> claimsJws = jwtTokenHelper.parseToken(token);
// 4. 获取用户名
// JJWT 0.12+ 建议使用 getPayload() 替代 getBody()
// 在 Helper 中生成 Token 时使用的是 .subject(username),所以这里取 Subject
String username = claimsJws.getPayload().getSubject();
// 4. 获取用户名
// JJWT 0.12+ 建议使用 getPayload() 替代 getBody()
// 在 Helper 中生成 Token 时使用的是 .subject(username),所以这里取 Subject
String username = claimsJws.getPayload().getSubject();
// 5. 组装认证信息 (如果当前上下文没有认证信息)
if (StringUtils.isNotBlank(username) && Objects.isNull(SecurityContextHolder.getContext().getAuthentication())) {
// 5. 组装认证信息 (如果当前上下文没有认证信息)
if (StringUtils.isNotBlank(username) && Objects.isNull(SecurityContextHolder.getContext().getAuthentication())) {
// 查询数据库获取用户完整信息 (包含权限)
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// 查询数据库获取用户完整信息 (包含权限)
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// 构建 Spring Security 的认证 Token
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
// 构建 Spring Security 的认证 Token
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// 6. 将认证信息存入 SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
// 6. 将认证信息存入 SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (AuthenticationException e) {
// 7. 异常处理
// 捕获 JwtTokenHelper 抛出的 BadCredentialsException 或 CredentialsExpiredException
// 如果 Token 存在但是无效/过期,直接交给 EntryPoint 处理响应 (通常返回 401)
// 并 return 结束当前过滤器,不再往下执行
authenticationEntryPoint.commence(request, response, e);
return;
} catch (Exception e) {
// 处理其他未预料到的异常
log.error("JWT处理过程中发生未知错误", e);
authenticationEntryPoint.commence(request, response, new AuthenticationException("系统内部认证错误") {
});
return;
}
} catch (AuthenticationException e) {
// 7. 异常处理
// 捕获 JwtTokenHelper 抛出的 BadCredentialsException 或 CredentialsExpiredException
// 如果 Token 存在但是无效/过期,直接交给 EntryPoint 处理响应 (通常返回 401)
// 并 return 结束当前过滤器,不再往下执行
authenticationEntryPoint.commence(request, response, e);
return;
} catch (Exception e) {
// 处理其他未预料到的异常
log.error("JWT处理过程中发生未知错误", e);
authenticationEntryPoint.commence(request, response, new AuthenticationException("系统内部认证错误") {
});
return;
}
}
}
// 8. 放行请求 (如果没有 Token 或者 Token 校验通过,继续执行下一个过滤器)
filterChain.doFilter(request, response);
// 8. 放行请求 (如果没有 Token 或者 Token 校验通过,继续执行下一个过滤器)
filterChain.doFilter(request, response);
} else {
filterChain.doFilter(request, response);
}
}
}