修复数据总线访问日志无法显示状态码问题: http://172.16.46.63:31560/index.php?m=task&f=view&taskID=703. databus 新增 client 统一出口内容管理审计: http://172.16.46.63:31560/index.php?m=task&f=view&taskID=716
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package com.zt.plat.module.databus.api;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.util.monitor.TracerUtils;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.framework.common.util.servlet.ServletUtils;
|
||||
import com.zt.plat.module.databus.api.dto.ApiAccessLogCreateReq;
|
||||
import com.zt.plat.module.databus.api.provider.DatabusAccessLogProviderApi;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiAccessLogDO;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiAccessLogService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
*
|
||||
* 2026/1/21 10:05
|
||||
*/
|
||||
@RestController
|
||||
public class DatabusAccessLogProviderApiImpl implements DatabusAccessLogProviderApi {
|
||||
|
||||
@Resource
|
||||
private ApiAccessLogService apiAccessLogService;
|
||||
|
||||
@Override
|
||||
@PermitAll
|
||||
public CommonResult<Boolean> add(Map<String, String> headers, ApiAccessLogCreateReq req) {
|
||||
ApiAccessLogDO logDO = new ApiAccessLogDO();
|
||||
BeanUtils.copyProperties(req, logDO);
|
||||
logDO.setTraceId(TracerUtils.getTraceId());
|
||||
logDO.setClientIp(ServletUtils.getClientIP());
|
||||
logDO.setCreateTime(LocalDateTime.now());
|
||||
logDO.setUpdateTime(LocalDateTime.now());
|
||||
logDO.setCreator("1");
|
||||
logDO.setUpdater("1");
|
||||
|
||||
apiAccessLogService.create(logDO);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
@@ -159,6 +159,7 @@ public class ApiGatewayAccessLogger {
|
||||
update.setStatus(resolveStatus(status));
|
||||
update.setResponseTime(LocalDateTime.now());
|
||||
update.setDuration(calculateDuration(request));
|
||||
update.setUpdater("1");
|
||||
apiAccessLogService.update(update);
|
||||
} catch (Exception ex) {
|
||||
log.warn("更新入口 API 访问日志失败, logId={}", logId, ex);
|
||||
|
||||
@@ -89,6 +89,7 @@ public class ApiGatewayExecutionService {
|
||||
} else {
|
||||
responseContext = apiFlowDispatcher.dispatch(context.getApiCode(), context.getApiVersion(), context);
|
||||
}
|
||||
responseContext.setResponseStatus(resolveStatus(responseContext));
|
||||
} catch (ServiceException ex) {
|
||||
errorProcessor.applyServiceException(context, ex);
|
||||
accessLogger.onException(context, ex);
|
||||
|
||||
@@ -77,6 +77,9 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加日志接口需要特殊处理
|
||||
boolean isNormalProcess = !pathMatcher.match("/databus/api/portal/access-log/**", pathWithinApplication);
|
||||
Long accessLogId = null;
|
||||
ApiGatewayProperties.Security security = properties.getSecurity();
|
||||
ApiClientCredentialDO credential = null;
|
||||
@@ -95,8 +98,10 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
accessLogger.finalizeEarly(request, HttpStatus.FORBIDDEN.value(), "IP 禁止访问");
|
||||
return;
|
||||
}
|
||||
// IP 校验通过后再补录入口日志,避免无租户信息写库
|
||||
accessLogId = accessLogger.logEntrance(request);
|
||||
// IP 校验通过后再补录入口日志,避免无租户信息写库, 非日志添加接口才记录日志
|
||||
if (isNormalProcess) {
|
||||
accessLogId = accessLogger.logEntrance(request);
|
||||
}
|
||||
if (!security.isEnabled()) {
|
||||
byte[] originalBody = StreamUtils.copyToByteArray(request.getInputStream());
|
||||
CachedBodyHttpServletRequest passthroughRequest = new CachedBodyHttpServletRequest(request, originalBody);
|
||||
@@ -128,13 +133,17 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
if (nonce.length() < 8) {
|
||||
throw new SecurityValidationException(HttpStatus.BAD_REQUEST, "随机数长度不足");
|
||||
}
|
||||
String signature = requireHeader(request, SIGNATURE_HEADER, "缺少签名");
|
||||
|
||||
// 尝试按凭证配置解密请求体,并构建签名载荷进行校验
|
||||
byte[] decryptedBody = decryptRequestBody(requestBody, credential, security);
|
||||
verifySignature(request, decryptedBody, signature, credential, security, appId, timestampHeader);
|
||||
if (isNormalProcess) {
|
||||
// 非日志添加接口才处理
|
||||
String signature = requireHeader(request, SIGNATURE_HEADER, "缺少签名");
|
||||
// 尝试按凭证配置解密请求体,并构建签名载荷进行校验
|
||||
byte[] decryptedBody = decryptRequestBody(requestBody, credential, security);
|
||||
verifySignature(request, decryptedBody, signature, credential, security, appId, timestampHeader);
|
||||
requestBody = decryptedBody;
|
||||
}
|
||||
ensureNonce(tenantId, appId, nonce, security);
|
||||
requestBody = decryptedBody;
|
||||
|
||||
}
|
||||
|
||||
// 使用可重复读取的请求包装,供后续过滤器继续消费
|
||||
@@ -154,7 +163,9 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
try {
|
||||
filterChain.doFilter(securedRequest, responseWrapper);
|
||||
dispatchedToGateway = true;
|
||||
encryptResponse(responseWrapper, credential, security);
|
||||
if (isNormalProcess) {
|
||||
encryptResponse(responseWrapper, credential, security);
|
||||
}
|
||||
} finally {
|
||||
responseWrapper.copyBodyToResponse();
|
||||
}
|
||||
@@ -163,7 +174,7 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
accessLogId = accessLogger.logEntrance(request);
|
||||
}
|
||||
log.warn("[API-PORTAL] 安全校验失败: {}", ex.getMessage());
|
||||
writeErrorResponse(response, security, credential, ex.status(), ex.getMessage());
|
||||
writeErrorResponse(response, security, credential, ex.status(), ex.getMessage(), isNormalProcess);
|
||||
if (!dispatchedToGateway) {
|
||||
accessLogger.finalizeEarly(request, ex.status().value(), ex.getMessage());
|
||||
}
|
||||
@@ -172,7 +183,7 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
accessLogId = accessLogger.logEntrance(request);
|
||||
}
|
||||
log.error("[API-PORTAL] 处理安全校验时出现异常", ex);
|
||||
writeErrorResponse(response, security, credential, HttpStatus.INTERNAL_SERVER_ERROR, "网关安全校验失败");
|
||||
writeErrorResponse(response, security, credential, HttpStatus.INTERNAL_SERVER_ERROR, "网关安全校验失败", isNormalProcess);
|
||||
if (!dispatchedToGateway) {
|
||||
accessLogger.finalizeEarly(request, HttpStatus.INTERNAL_SERVER_ERROR.value(), "网关安全校验失败");
|
||||
}
|
||||
@@ -479,6 +490,7 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
String token = tokenOptional.get();
|
||||
securedRequest.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token);
|
||||
securedRequest.setHeader(GatewayJwtResolver.HEADER_ZT_AUTH_TOKEN, token);
|
||||
|
||||
}
|
||||
|
||||
private static final class SecurityValidationException extends RuntimeException {
|
||||
@@ -499,7 +511,8 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
ApiGatewayProperties.Security security,
|
||||
ApiClientCredentialDO credential,
|
||||
HttpStatus status,
|
||||
String message) {
|
||||
String message,
|
||||
boolean isNormalProcess) {
|
||||
if (response.isCommitted()) {
|
||||
log.warn("[API-PORTAL] 响应已提交,无法写入安全校验错误: {}", message);
|
||||
return;
|
||||
@@ -514,7 +527,7 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
.response(null)
|
||||
.traceId(traceId)
|
||||
.build();
|
||||
if (shouldEncryptErrorResponse(security, credential)) {
|
||||
if (shouldEncryptErrorResponse(security, credential) && isNormalProcess) {
|
||||
String encryptionKey = credential.getEncryptionKey();
|
||||
String encryptionType = resolveEncryptionType(credential, security);
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user