package com.zy.acs.manager.common.interceptor; import com.zy.acs.framework.common.Cools; import com.zy.acs.manager.common.annotation.IntegrationAuth; 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.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_APP_AUTH = "appAuth"; private static final String ATTR_AUTH_MEMO = "integrationAuthMemo"; private static final String ATTR_CACHE = "cache"; private static final String ATTR_START_AT = "openApiStartTime"; @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) { log.debug("Skip open-api logging for {} because @IntegrationAuth is missing", handlerMethod.getMethod()); return true; } request.setAttribute(ATTR_APP_AUTH, integrationAuth.value()); if (!Cools.isEmpty(integrationAuth.memo())) { request.setAttribute(ATTR_AUTH_MEMO, integrationAuth.memo()); } request.setAttribute(ATTR_START_AT, System.currentTimeMillis()); request.setAttribute(ATTR_CACHE, buildRequestCache(request)); return true; } 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("parameters", flattenParameters(request.getParameterMap())); cache.put("headers", extractHeaders(request)); String body = readBody(request); if (!Cools.isEmpty(body)) { cache.put("body", body); } return 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<>(); List names = Collections.list(request.getHeaderNames()); 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; } } }