refactor: 统一错误处理并优化代码
- 移除重复的错误提示,统一在axios拦截器中处理 - 优化XSS拦截器,添加请求头白名单 - 修复注册码服务的日期处理问题 - 添加403权限错误处理 - 优化分组查询参数处理
This commit is contained in:
@@ -7,6 +7,7 @@ import com.test.bijihoudaun.common.response.ResultCode;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authorization.AuthorizationDeniedException;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
@@ -71,6 +72,13 @@ public class GlobalExceptionHandler {
|
||||
return R.fail(ResultCode.VALIDATE_FAILED.getCode(), "参数错误");
|
||||
}
|
||||
|
||||
// 修复:添加权限拒绝异常处理
|
||||
@ExceptionHandler(AuthorizationDeniedException.class)
|
||||
public R<Void> handleAuthorizationDeniedException(AuthorizationDeniedException e, HttpServletRequest request) {
|
||||
log.warn("Access denied at {}: {}", request.getRequestURI(), e.getMessage());
|
||||
return R.fail(ResultCode.FORBIDDEN.getCode(), "无权操作,需要管理员权限");
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public R<Void> handleException(Exception e, HttpServletRequest request) {
|
||||
log.error("Unexpected error at {} - Error type: {}", request.getRequestURI(), e.getClass().getSimpleName());
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
@@ -22,6 +23,7 @@ import java.util.Arrays;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity(prePostEnabled = true)
|
||||
public class SecurityConfig {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
@@ -10,7 +10,11 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* XSS 过滤拦截器
|
||||
@@ -21,6 +25,29 @@ import java.util.Enumeration;
|
||||
@Slf4j
|
||||
public class XSSInterceptor implements HandlerInterceptor {
|
||||
|
||||
// 修复:添加不需要检查的请求头白名单(浏览器标准请求头)
|
||||
private static final Set<String> HEADER_WHITELIST = new HashSet<>(Arrays.asList(
|
||||
"sec-ch-ua",
|
||||
"sec-ch-ua-mobile",
|
||||
"sec-ch-ua-platform",
|
||||
"sec-fetch-dest",
|
||||
"sec-fetch-mode",
|
||||
"sec-fetch-site",
|
||||
"sec-fetch-user",
|
||||
"user-agent",
|
||||
"accept",
|
||||
"accept-encoding",
|
||||
"accept-language",
|
||||
"cache-control",
|
||||
"connection",
|
||||
"host",
|
||||
"referer",
|
||||
"upgrade-insecure-requests",
|
||||
"content-type",
|
||||
"content-length",
|
||||
"origin"
|
||||
));
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 过滤请求头,发现 XSS 攻击则拒绝请求
|
||||
@@ -46,6 +73,10 @@ public class XSSInterceptor implements HandlerInterceptor {
|
||||
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = headerNames.nextElement();
|
||||
// 修复:跳过白名单中的请求头
|
||||
if (HEADER_WHITELIST.contains(headerName.toLowerCase())) {
|
||||
continue;
|
||||
}
|
||||
String headerValue = request.getHeader(headerName);
|
||||
if (StrUtil.isNotBlank(headerValue)) {
|
||||
String filteredValue = HtmlUtil.filter(headerValue);
|
||||
@@ -84,8 +115,12 @@ public class XSSInterceptor implements HandlerInterceptor {
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
response.setStatus(400);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
response.getWriter().write(mapper.writeValueAsString(
|
||||
R.fail(ResultCode.FAILED.getCode(), message)
|
||||
));
|
||||
// 修复:使用 try-with-resources 确保 PrintWriter 关闭
|
||||
try (PrintWriter writer = response.getWriter()) {
|
||||
writer.write(mapper.writeValueAsString(
|
||||
R.fail(ResultCode.FAILED.getCode(), message)
|
||||
));
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@ import org.apache.ibatis.annotations.Select;
|
||||
@Mapper
|
||||
public interface UserMapper extends BaseMapper<User> {
|
||||
// 自定义查询方法示例
|
||||
@Select("SELECT id, `username`, `password`, `email`, created_at, updated_at, `token`, token_enddata FROM `user` WHERE username = #{username}")
|
||||
@Select("SELECT id, `username`, `password`, `email`, `role`, created_at, updated_at, `token`, token_enddata FROM `user` WHERE username = #{username}")
|
||||
User findByUsername(String username);
|
||||
}
|
||||
@@ -18,14 +18,18 @@ import java.util.UUID;
|
||||
@Transactional
|
||||
public class RegistrationCodeServiceImpl extends ServiceImpl<RegistrationCodeMapper, RegistrationCode> implements RegistrationCodeService {
|
||||
|
||||
// 修复:定义日期时间格式器
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public String generateCode(String creator) {
|
||||
RegistrationCode registrationCode = new RegistrationCode();
|
||||
String code = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
|
||||
registrationCode.setCode(code);
|
||||
registrationCode.setCreatedBy(creator);
|
||||
registrationCode.setCreatedAt(LocalDateTime.now().toString());
|
||||
registrationCode.setExpiryTime(LocalDateTime.now().plusDays(1).toString());
|
||||
// 修复:使用格式化后的日期字符串
|
||||
registrationCode.setCreatedAt(LocalDateTime.now().format(DATE_TIME_FORMATTER));
|
||||
registrationCode.setExpiryTime(LocalDateTime.now().plusDays(1).format(DATE_TIME_FORMATTER));
|
||||
save(registrationCode);
|
||||
return code;
|
||||
}
|
||||
@@ -41,9 +45,16 @@ public class RegistrationCodeServiceImpl extends ServiceImpl<RegistrationCodeMap
|
||||
return false;
|
||||
}
|
||||
|
||||
LocalDateTime expiryTime = LocalDateTime.parse(registrationCode.getExpiryTime());
|
||||
if (expiryTime.isBefore(LocalDateTime.now())) {
|
||||
remove(queryWrapper); // 注册码过期,删除
|
||||
try {
|
||||
// 修复:使用格式器解析日期
|
||||
LocalDateTime expiryTime = LocalDateTime.parse(registrationCode.getExpiryTime(), DATE_TIME_FORMATTER);
|
||||
if (expiryTime.isBefore(LocalDateTime.now())) {
|
||||
remove(queryWrapper); // 注册码过期,删除
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 如果解析失败(可能是旧数据格式),认为已过期
|
||||
remove(queryWrapper);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -55,6 +66,7 @@ public class RegistrationCodeServiceImpl extends ServiceImpl<RegistrationCodeMap
|
||||
@Override
|
||||
@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行
|
||||
public void deleteExpiredCodes() {
|
||||
remove(new QueryWrapper<RegistrationCode>().lt("expiry_time", LocalDateTime.now().toString()));
|
||||
// 修复:使用格式化后的日期字符串进行比较
|
||||
remove(new QueryWrapper<RegistrationCode>().lt("expiry_time", LocalDateTime.now().format(DATE_TIME_FORMATTER)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user