package com.zy.acs.manager.common.interceptor; import com.zy.acs.framework.common.Cools; import com.zy.acs.manager.common.annotation.IntegrationAuth; import com.zy.acs.manager.core.domain.type.NamespaceType; import lombok.Value; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.util.ContentCachingRequestWrapper; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Intercepts open API calls so they can be audited via IntegrationRecordAdvice. */ @Slf4j @Component public class IntegrationOpenApiInterceptor implements HandlerInterceptor { private static final String ATTR_CONTEXT = IntegrationOpenApiInterceptor.class.getName() + ".CONTEXT"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (!(handler instanceof HandlerMethod)) { return true; } HandlerMethod handlerMethod = (HandlerMethod) handler; IntegrationAuth integrationAuth = findIntegrationAuth(handlerMethod); if (integrationAuth == null || integrationAuth.value() == IntegrationAuth.Enable.SKIP_LOG) { return true; } NamespaceType namespaceType = integrationAuth.name() == null ? NamespaceType.NONE : integrationAuth.name(); IntegrationRequestContext context = new IntegrationRequestContext( namespaceType, namespaceType.name, handlerMethod.getBeanType().getSimpleName() + "#" + handlerMethod.getMethod().getName(), request.getMethod(), request.getRequestURI(), request.getQueryString(), System.currentTimeMillis(), buildRequestCache(request) ); request.setAttribute(ATTR_CONTEXT, context); return true; } public static IntegrationRequestContext getContext(HttpServletRequest request) { Object attribute = request.getAttribute(ATTR_CONTEXT); if (attribute instanceof IntegrationRequestContext) { return (IntegrationRequestContext) attribute; } return null; } private IntegrationAuth findIntegrationAuth(HandlerMethod handlerMethod) { IntegrationAuth annotation = AnnotatedElementUtils.findMergedAnnotation(handlerMethod.getMethod(), IntegrationAuth.class); if (annotation != null) { return annotation; } return AnnotatedElementUtils.findMergedAnnotation(handlerMethod.getBeanType(), IntegrationAuth.class); } private Map buildRequestCache(HttpServletRequest request) { Map cache = new LinkedHashMap<>(); cache.put("method", request.getMethod()); cache.put("uri", request.getRequestURI()); cache.put("query", request.getQueryString()); cache.put("contentType", request.getContentType()); cache.put("parameters", flattenParameters(request.getParameterMap())); cache.put("headers", extractHeaders(request)); String body = readBody(request); if (!Cools.isEmpty(body)) { cache.put("body", body); } return Collections.unmodifiableMap(cache); } private Map flattenParameters(Map rawParams) { Map flattened = new LinkedHashMap<>(); if (rawParams == null) { return flattened; } rawParams.forEach((key, values) -> { if (values == null) { flattened.put(key, null); } else if (values.length == 1) { flattened.put(key, values[0]); } else { flattened.put(key, Arrays.asList(values)); } }); return flattened; } private Map extractHeaders(HttpServletRequest request) { Map headers = new LinkedHashMap<>(); Enumeration headerNames = request.getHeaderNames(); if (headerNames == null) { return headers; } List names = Collections.list(headerNames); for (String name : names) { headers.put(name, request.getHeader(name)); } return headers; } private String readBody(HttpServletRequest request) { if (request instanceof ContentCachingRequestWrapper) { ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request; byte[] buffer = wrapper.getContentAsByteArray(); if (buffer.length > 0) { Charset charset = charset(wrapper.getCharacterEncoding()); return new String(buffer, charset); } } return null; } private Charset charset(String encoding) { if (Cools.isEmpty(encoding)) { return StandardCharsets.UTF_8; } try { return Charset.forName(encoding); } catch (Exception e) { return StandardCharsets.UTF_8; } } @Value public static class IntegrationRequestContext { NamespaceType namespaceType; String namespace; String handler; String method; String uri; String query; long startAt; Map requestSnapshot; } }