|
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}");
|
}
|
}
|