package com.malk.controller; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * 生产管理接口保护:默认关闭;临时开启时必须同时配置并携带管理令牌。 */ @Slf4j @Configuration public class AdminEndpointGuardConfig implements WebMvcConfigurer { static final String TOKEN_HEADER = "X-AKDS-Admin-Token"; static final List PROTECTED_PATHS = Collections.unmodifiableList(Arrays.asList( "/workhours/**", "/personnel-sync/**", "/approval/writeback/sync", "/approval/resubmit", "/timecard/summary/cleanup-duplicates", "/timecard/summary/delete-instances" )); @Value("${admin-api.enabled:false}") private boolean enabled; @Value("${admin-api.token:}") private String token; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AdminEndpointInterceptor(enabled, token)) .addPathPatterns(PROTECTED_PATHS); } static final class AdminEndpointInterceptor implements HandlerInterceptor { private final boolean enabled; private final String expectedToken; AdminEndpointInterceptor(boolean enabled, String expectedToken) { this.enabled = enabled; this.expectedToken = expectedToken; } @Override public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { response.setHeader("Cache-Control", "no-store"); if (!enabled) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return false; } String actualToken = request.getHeader(TOKEN_HEADER); if (!tokenMatches(expectedToken, actualToken)) { log.warn("[AdminAPI] 管理接口鉴权失败 method={} path={} remote={}", request.getMethod(), request.getRequestURI(), request.getRemoteAddr()); response.sendError(HttpServletResponse.SC_FORBIDDEN); return false; } return true; } } static boolean tokenMatches(String expectedToken, String actualToken) { if (StringUtils.isBlank(expectedToken) || StringUtils.isBlank(actualToken)) { return false; } return MessageDigest.isEqual( expectedToken.getBytes(StandardCharsets.UTF_8), actualToken.getBytes(StandardCharsets.UTF_8)); } }