fix(后端): 请求日志敏感信息脱敏

- 添加请求参数脱敏功能,对 password、token 等敏感字段进行掩码处理
- 响应结果中的敏感信息同样脱敏
- 敏感字段列表:password, pwd, secret, token, accessToken, refreshToken, oldPassword, newPassword, confirmPassword
- 脱敏掩码:***

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
En 2026-03-26 15:03:27 +08:00
parent 79d98be366
commit c73bae7104

View File

@ -1,6 +1,7 @@
package com.lesingle.edu.common.aspect;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.lesingle.edu.common.security.SecurityUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
@ -18,13 +19,26 @@ import java.util.Objects;
/**
* 请求日志切面
* 记录所有 Controller 层的请求信息
* 记录所有 Controller 层的请求信息敏感信息已脱敏
*/
@Slf4j
@Aspect
@Component
public class RequestLogAspect {
/**
* 敏感字段列表不区分大小写
*/
private static final String[] SENSITIVE_FIELDS = {
"password", "pwd", "secret", "token", "accessToken", "refreshToken",
"oldPassword", "newPassword", "confirmPassword"
};
/**
* 脱敏掩码
*/
private static final String MASK = "***";
/**
* 定义切点Controller 层所有方法
*/
@ -62,7 +76,8 @@ public class RequestLogAspect {
String methodType = request.getMethod();
String className = joinPoint.getTarget().getClass().getName();
String methodName = method.getName();
String params = JSON.toJSONString(getRequestParams(joinPoint));
// 请求参数脱敏处理
String params = desensitize(getRequestParams(joinPoint));
log.info("===== 请求开始 [userId={}, role={}] =====", userId, role);
log.info("接口地址:{} {}", methodType, requestURI);
@ -77,7 +92,7 @@ public class RequestLogAspect {
// 记录响应结果
log.info("响应时间:{}ms", duration);
log.info("响应结果:{}", JSON.toJSONString(result));
log.info("响应结果:{}", desensitize(result));
log.info("===== 请求结束 [userId={}, role={}] =====", userId, role);
return result;
@ -111,4 +126,72 @@ public class RequestLogAspect {
return args;
}
}
/**
* 请求参数脱敏处理
* 将敏感字段 passwordtoken 替换为 ***
*
* @param original 原始参数对象
* @return 脱敏后的 JSON 字符串
*/
private String desensitize(Object original) {
if (original == null) {
return null;
}
try {
// 转换为 JSONObject 以便修改
String jsonStr = JSON.toJSONString(original);
JSONObject jsonObject = JSON.parseObject(jsonStr);
if (jsonObject != null) {
maskSensitiveFields(jsonObject);
return jsonObject.toJSONString();
}
return jsonStr;
} catch (Exception e) {
// 解析失败时返回原始 JSON
log.warn("请求参数脱敏失败:{}", e.getMessage());
return JSON.toJSONString(original);
}
}
/**
* 递归掩码敏感字段
*
* @param jsonObject 要处理的 JSON 对象
*/
private void maskSensitiveFields(JSONObject jsonObject) {
if (jsonObject == null) {
return;
}
for (String key : jsonObject.keySet()) {
if (isSensitiveField(key)) {
jsonObject.put(key, MASK);
} else {
// 递归处理嵌套的 JSONObject
Object value = jsonObject.get(key);
if (value instanceof JSONObject) {
maskSensitiveFields((JSONObject) value);
}
}
}
}
/**
* 判断字段名是否为敏感字段
*
* @param fieldName 字段名
* @return true 如果是敏感字段
*/
private boolean isSensitiveField(String fieldName) {
if (fieldName == null) {
return false;
}
String lowerFieldName = fieldName.toLowerCase();
for (String sensitiveField : SENSITIVE_FIELDS) {
if (lowerFieldName.equals(sensitiveField.toLowerCase())) {
return true;
}
}
return false;
}
}