// 幂等拦截器中添加签名校验逻辑
private void validateSign(HttpServletRequest request, String requestId, Long userId) {
// 1. 获取前端传递的时间戳和签名
String timestampStr = request.getHeader("Idempotent-Timestamp");
String sign = request.getHeader("Idempotent-Sign");
if (timestampStr == null || sign == null) {
throw new IdempotentException("缺少幂等签名信息,请规范请求!");
}
// 2. 校验时间戳(有效期5分钟,防止重放攻击)
long timestamp = Long.parseLong(timestampStr);
long currentTime = System.currentTimeMillis() / 1000;
if (Math.abs(currentTime - timestamp) > 300) { // 5分钟=300秒
throw new IdempotentException("请求已过期,请重新发起!");
}
// 3. 后端重新计算签名(与前端规则一致)
String secretKey = "your-frontend-secret"; // 企业级推荐动态下发,而非固定
String signStr = String.format("%s%s%s%s", requestId, userId, timestampStr, secretKey);
String serverSign = DigestUtils.md5DigestAsHex(signStr.getBytes(StandardCharsets.UTF_8));
// 4. 比对签名(不相等则为伪造)
if (!serverSign.equalsIgnoreCase(sign)) {
throw new IdempotentException("幂等签名非法,请求被拒绝!");
}
}
// 在preHandle方法中调用签名校验
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// ... 省略前面的逻辑(获取requestId、解析userId) ...
// 敏感场景添加签名校验
validateSign(request, requestId, userId);
// ... 后续Redis校验逻辑 ...
}