fix: 优化移动端校验

This commit is contained in:
2026-07-08 10:35:48 +08:00
parent 095ab09750
commit 775fadea45

View File

@@ -2,22 +2,22 @@ package com.youlai.boot.framework.security.filter;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil; import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import com.youlai.boot.common.result.Result;
import com.youlai.boot.common.result.ResultCode; import com.youlai.boot.common.result.ResultCode;
import com.youlai.boot.common.result.ResponseWriter;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.function.Predicate;
/** /**
* 移动设备API签名验证过滤器 * 移动设备API签名验证过滤器
@@ -68,20 +68,20 @@ public class MobileApiSignatureFilter extends OncePerRequestFilter {
// 1. 获取设备标识 // 1. 获取设备标识
String deviceId = request.getHeader(HEADER_DEVICE_ID); String deviceId = request.getHeader(HEADER_DEVICE_ID);
if (StrUtil.isBlank(deviceId)) { if (StrUtil.isBlank(deviceId)) {
ResponseWriter.writeSuccess(response, ResultCode.MOBILE_DEVICE_ID_REQUIRED); writeErrorResponse(response, ResultCode.MOBILE_DEVICE_ID_REQUIRED);
return; return;
} }
// 获取随机数 // 获取随机数
String nonce = request.getHeader(HEADER_NONCE); String nonce = request.getHeader(HEADER_NONCE);
if (StrUtil.isBlank(nonce)) { if (StrUtil.isBlank(nonce)) {
ResponseWriter.writeSuccess(response, ResultCode.MOBILE_NONCE_REQUIRED); writeErrorResponse(response, ResultCode.MOBILE_NONCE_REQUIRED);
return; return;
} }
// 2. 获取时间戳 // 2. 获取时间戳
String timestampStr = request.getHeader(HEADER_TIMESTAMP); String timestampStr = request.getHeader(HEADER_TIMESTAMP);
if (StrUtil.isBlank(timestampStr)) { if (StrUtil.isBlank(timestampStr)) {
ResponseWriter.writeSuccess(response, ResultCode.MOBILE_TIMESTAMP_REQUIRED); writeErrorResponse(response, ResultCode.MOBILE_TIMESTAMP_REQUIRED);
return; return;
} }
@@ -89,28 +89,28 @@ public class MobileApiSignatureFilter extends OncePerRequestFilter {
try { try {
timestamp = Long.parseLong(timestampStr); timestamp = Long.parseLong(timestampStr);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
ResponseWriter.writeSuccess(response, ResultCode.MOBILE_TIMESTAMP_INVALID); writeErrorResponse(response, ResultCode.MOBILE_TIMESTAMP_INVALID);
return; return;
} }
// 3. 验证时间戳是否在有效期内 // 3. 验证时间戳是否在有效期内
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if (Math.abs(currentTime - timestamp) > SIGN_VALID_DURATION) { if (Math.abs(currentTime - timestamp) > SIGN_VALID_DURATION) {
ResponseWriter.writeSuccess(response, ResultCode.MOBILE_TIMESTAMP_EXPIRED); writeErrorResponse(response, ResultCode.MOBILE_TIMESTAMP_EXPIRED);
return; return;
} }
// 4. 获取签名 // 4. 获取签名
String sign = request.getHeader(HEADER_SIGN); String sign = request.getHeader(HEADER_SIGN);
if (StrUtil.isBlank(sign)) { if (StrUtil.isBlank(sign)) {
ResponseWriter.writeSuccess(response, ResultCode.MOBILE_SIGN_REQUIRED); writeErrorResponse(response, ResultCode.MOBILE_SIGN_REQUIRED);
return; return;
} }
// 5. 获取设备密钥从Redis或数据库 // 5. 获取设备密钥从Redis或数据库
// String deviceSecret = getDeviceSecret(deviceId); // String deviceSecret = getDeviceSecret(deviceId);
// if (StrUtil.isBlank(deviceSecret)) { // if (StrUtil.isBlank(deviceSecret)) {
// ResponseWriter.writeSuccess(response, ResultCode.MOBILE_DEVICE_NOT_REGISTERED); // writeErrorResponse(response, ResultCode.MOBILE_DEVICE_NOT_REGISTERED);
// return; // return;
// } // }
@@ -118,7 +118,7 @@ public class MobileApiSignatureFilter extends OncePerRequestFilter {
String expectedSign = generateSign(request); String expectedSign = generateSign(request);
logger.info("Expected sign: " + expectedSign); logger.info("Expected sign: " + expectedSign);
if (!sign.equals(expectedSign)) { if (!sign.equals(expectedSign)) {
ResponseWriter.writeSuccess(response, ResultCode.MOBILE_SIGN_INVALID); writeErrorResponse(response, ResultCode.MOBILE_SIGN_INVALID);
return; return;
} }
@@ -184,4 +184,12 @@ public class MobileApiSignatureFilter extends OncePerRequestFilter {
// 3. 生成MD5签名 // 3. 生成MD5签名
return DigestUtil.sha256Hex(sb.toString()); return DigestUtil.sha256Hex(sb.toString());
} }
private void writeErrorResponse(HttpServletResponse response, ResultCode resultCode) throws IOException {
response.setStatus(HttpStatus.BAD_REQUEST.value());
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
Result<?> result = Result.failed(resultCode);
response.getWriter().write(JSONUtil.toJsonStr(result));
}
} }