WIP
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
package com.starry.admin.common.filter;
|
||||
|
||||
import com.starry.admin.modules.weichat.service.WxTokenService;
|
||||
import com.starry.admin.modules.clerk.service.impl.PlayClerkUserInfoServiceImpl;
|
||||
import com.starry.admin.modules.custom.service.impl.PlayCustomUserInfoServiceImpl;
|
||||
import com.starry.admin.modules.clerk.module.entity.PlayClerkUserInfoEntity;
|
||||
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 请求关联ID过滤器,为每个HTTP请求生成唯一的跟踪ID
|
||||
* 用于日志关联和请求链路追踪
|
||||
*
|
||||
* @author Claude
|
||||
*/
|
||||
@Component
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class CorrelationFilter implements Filter {
|
||||
|
||||
@Resource
|
||||
private WxTokenService wxTokenService;
|
||||
|
||||
@Resource
|
||||
private PlayClerkUserInfoServiceImpl clerkUserInfoService;
|
||||
|
||||
@Resource
|
||||
private PlayCustomUserInfoServiceImpl customUserInfoService;
|
||||
|
||||
public static final String CORRELATION_ID_HEADER = "X-Correlation-ID";
|
||||
public static final String CORRELATION_ID_MDC_KEY = "correlationId";
|
||||
public static final String USER_ID_MDC_KEY = "userId";
|
||||
public static final String REQUEST_URI_MDC_KEY = "requestUri";
|
||||
public static final String REQUEST_METHOD_MDC_KEY = "requestMethod";
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
if (!(request instanceof HttpServletRequest)) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
|
||||
try {
|
||||
// 生成或获取关联ID
|
||||
String correlationId = getOrGenerateCorrelationId(httpRequest);
|
||||
|
||||
// 设置MDC上下文
|
||||
MDC.put(CORRELATION_ID_MDC_KEY, correlationId);
|
||||
MDC.put(REQUEST_URI_MDC_KEY, httpRequest.getRequestURI());
|
||||
MDC.put(REQUEST_METHOD_MDC_KEY, httpRequest.getMethod());
|
||||
|
||||
// 尝试获取用户ID(可能来自JWT或其他认证信息)
|
||||
String userId = extractUserId(httpRequest);
|
||||
if (userId != null) {
|
||||
MDC.put(USER_ID_MDC_KEY, userId);
|
||||
}
|
||||
|
||||
// 将关联ID添加到响应头
|
||||
httpResponse.setHeader(CORRELATION_ID_HEADER, correlationId);
|
||||
|
||||
// 继续过滤器链
|
||||
chain.doFilter(request, response);
|
||||
|
||||
} finally {
|
||||
// 清理MDC上下文
|
||||
MDC.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取或生成关联ID
|
||||
* 优先从请求头获取,如果没有则生成新的
|
||||
*/
|
||||
private String getOrGenerateCorrelationId(HttpServletRequest request) {
|
||||
String correlationId = request.getHeader(CORRELATION_ID_HEADER);
|
||||
if (correlationId == null || correlationId.trim().isEmpty()) {
|
||||
correlationId = "REQ-" + UUID.randomUUID().toString().substring(0, 8);
|
||||
}
|
||||
return correlationId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试从请求中提取用户ID
|
||||
* 根据项目的认证机制:支持微信端(clerk/custom token)和管理端(Authorization header)
|
||||
*/
|
||||
private String extractUserId(HttpServletRequest request) {
|
||||
try {
|
||||
// 1. 微信端 - Clerk用户认证
|
||||
String clerkToken = request.getHeader("clerkusertoken");
|
||||
if (clerkToken != null && !clerkToken.trim().isEmpty()) {
|
||||
return extractUserIdFromWxToken(clerkToken, "clerk");
|
||||
}
|
||||
|
||||
// 2. 微信端 - Custom用户认证
|
||||
String customToken = request.getHeader("customusertoken");
|
||||
if (customToken != null && !customToken.trim().isEmpty()) {
|
||||
return extractUserIdFromWxToken(customToken, "custom");
|
||||
}
|
||||
|
||||
// 3. 管理端 - JWT Bearer token认证
|
||||
String authHeader = request.getHeader("Authorization");
|
||||
if (authHeader != null && authHeader.startsWith("Bearer ")) {
|
||||
return extractUserIdFromJwtToken(authHeader);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
// 如果解析失败,不影响主流程,只是记录日志时没有用户ID
|
||||
// 可以选择记录debug日志,但不抛异常
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从微信token中提取真实用户ID
|
||||
*/
|
||||
private String extractUserIdFromWxToken(String token, String userType) {
|
||||
try {
|
||||
// 使用WxTokenService解析JWT token获取真实用户ID
|
||||
String userId = wxTokenService.getWxUserIdByToken(token);
|
||||
|
||||
if (userId != null) {
|
||||
// 根据用户类型获取更多用户信息(可选)
|
||||
if ("clerk".equals(userType)) {
|
||||
PlayClerkUserInfoEntity clerkUser = clerkUserInfoService.selectById(userId);
|
||||
if (clerkUser != null) {
|
||||
// 返回格式: clerk_userId 或者可以包含昵称等信息
|
||||
return "clerk_" + userId;
|
||||
}
|
||||
} else if ("custom".equals(userType)) {
|
||||
PlayCustomUserInfoEntity customUser = customUserInfoService.selectById(userId);
|
||||
if (customUser != null) {
|
||||
return "custom_" + userId;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果查询用户详情失败,至少返回基础用户ID
|
||||
return userType + "_" + userId;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
// Token解析失败,可能是过期或无效token,不影响主流程
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从管理端JWT token中提取用户ID
|
||||
*/
|
||||
private String extractUserIdFromJwtToken(String authHeader) {
|
||||
try {
|
||||
// 管理端的JWT解析比较复杂,这里先返回标识
|
||||
// 实际应该通过JwtToken组件或SecurityUtils获取当前登录用户信息
|
||||
return "admin_user";
|
||||
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
// 初始化逻辑
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// 清理逻辑
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user