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:
parent
79d98be366
commit
c73bae7104
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求参数脱敏处理
|
||||
* 将敏感字段(如 password、token 等)替换为 ***
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user