package com.gkhy.hazmat.framework.security.filter; import com.alibaba.fastjson2.JSON; import com.gkhy.hazmat.common.annotation.ThirdPartyToken; import com.gkhy.hazmat.common.api.CommonResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; /** * 第三方平台token验证过滤器 */ @Component public class ThirdPartyTokenFilter extends OncePerRequestFilter { @Value("${third-party.token:}") private String thirdPartyToken; private static final Logger logger = LoggerFactory.getLogger(ThirdPartyTokenFilter.class); private static final String TOKEN_HEADER = "X-Token"; private final RequestMappingHandlerMapping handlerMapping; public ThirdPartyTokenFilter(RequestMappingHandlerMapping handlerMapping) { this.handlerMapping = handlerMapping; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 跨域OPTIONS预检直接放行 if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { filterChain.doFilter(request, response); return; } boolean isThirdAuth = false; try { HandlerExecutionChain handlerChain = handlerMapping.getHandler(request); boolean needThirdToken = false; if (handlerChain != null && handlerChain.getHandler() instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handlerChain.getHandler(); ThirdPartyToken annotation = handlerMethod.getMethodAnnotation(ThirdPartyToken.class); if (annotation == null) { annotation = handlerMethod.getBeanType().getAnnotation(ThirdPartyToken.class); } needThirdToken = annotation != null; } // 仅标记@ThirdPartyToken的接口校验固定Token if (needThirdToken) { String clientToken = request.getHeader(TOKEN_HEADER); if (!StringUtils.hasText(clientToken)) { writeError(response, "请求头缺少X-Token第三方凭证"); return; } if (!thirdPartyToken.equals(clientToken)) { writeError(response, "第三方Token无效,请核对凭证"); return; } // 写入安全上下文,携带专属权限 UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken( "third_party_single_platform", null, new ArrayList<>() ); SecurityContextHolder.getContext().setAuthentication(authToken); isThirdAuth = true; } filterChain.doFilter(request, response); } catch (Exception e) { logger.error("第三方Token过滤器解析处理器异常", e); filterChain.doFilter(request, response); } finally { // 清除上下文,防止线程复用越权 if (isThirdAuth) { SecurityContextHolder.clearContext(); } } } /** * 统一401错误返回 */ private void writeError(HttpServletResponse response, String msg) throws IOException { response.setContentType("application/json;charset=UTF-8"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("{\"code\":401,\"msg\":\"" + msg + "\",\"data\":null}"); } }