lrj
9 小时以前 ae3349d2ff53767b5bc9cb30e1bf7e15f9e814ee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package com.rongyichuang.auth.filter;
 
import com.rongyichuang.auth.util.JwtUtil;
import com.rongyichuang.user.entity.User;
import com.rongyichuang.user.repository.UserRepository;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
 
import java.io.IOException;
import java.util.ArrayList;
import java.util.Optional;
 
/**
 * JWT认证过滤器
 */
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
 
    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
 
    @Autowired
    private JwtUtil jwtUtil;
 
    @Autowired
    private UserRepository userRepository;
    
    /**
     * 判断是否应该跳过JWT认证
     */
    private boolean shouldSkipAuthentication(String requestURI) {
        // 这些路径不需要JWT认证(已去掉context path)
        String[] skipPaths = {
            "/auth/",
            "/actuator/",
            "/test/",
            "/cleanup/",
            "/upload/",
            "/graphql",
            "/graphiql"
        };
        
        for (String path : skipPaths) {
            if (requestURI.startsWith(path)) {
                return true;
            }
        }
        
        return false;
    }
 
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, 
                                    FilterChain filterChain) throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        String contextPath = request.getContextPath();
        
        // 去掉context path,与Spring Security的行为保持一致
        String pathWithoutContext = requestURI;
        if (contextPath != null && !contextPath.isEmpty() && requestURI.startsWith(contextPath)) {
            pathWithoutContext = requestURI.substring(contextPath.length());
        }
        
        System.out.println("=== JWT过滤器被调用 === 原始URI: " + requestURI + ", 去掉context path后: " + pathWithoutContext);
        logger.debug("JWT过滤器开始处理请求: {}", pathWithoutContext);
        
        // 跳过不需要认证的路径
        if (shouldSkipAuthentication(pathWithoutContext)) {
            logger.debug("跳过JWT认证,路径: {}", pathWithoutContext);
            filterChain.doFilter(request, response);
            return;
        }
        
        String authHeader = request.getHeader("Authorization");
        String token = null;
        Long userId = null;
 
        logger.debug("Authorization头: {}", authHeader);
 
        // 从请求头中提取JWT token
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            token = authHeader.substring(7);
            logger.debug("提取到JWT token: {}", token.substring(0, Math.min(20, token.length())) + "...");
            try {
                userId = jwtUtil.getUserIdFromToken(token);
                logger.debug("从token中解析到用户ID: {}", userId);
            } catch (Exception e) {
                logger.error("JWT token解析失败: {}", e.getMessage(), e);
            }
        } else {
            logger.debug("没有找到Authorization头或格式不正确");
        }
 
        // 如果token有效且当前是匿名或无认证,则进行认证
        Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
        boolean isAnonymous = (existingAuth == null) || ("anonymousUser".equals(String.valueOf(existingAuth.getPrincipal())));
        if (userId != null && isAnonymous) {
            logger.debug("开始验证token有效性");
            
            // 验证token是否有效
            if (jwtUtil.validateToken(token)) {
                logger.debug("Token验证成功,查找用户信息");
                
                // 查找用户信息
                Optional<User> userOpt = userRepository.findById(userId);
                if (userOpt.isPresent()) {
                    User user = userOpt.get();
                    logger.debug("找到用户: userId={}, phone={}", user.getId(), user.getPhone());
                    
                    // 创建认证对象
                    UsernamePasswordAuthenticationToken authToken = 
                        new UsernamePasswordAuthenticationToken(
                            user.getId().toString(), 
                            null, 
                            new ArrayList<>() // 暂时不设置权限,后续可以根据角色设置
                        );
                    
                    authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authToken);
                    
                    logger.info("用户认证成功: userId={}, phone={}", user.getId(), user.getPhone());
                } else {
                    logger.warn("用户不存在: userId={}", userId);
                }
            } else {
                logger.warn("Token验证失败");
            }
        } else if (userId == null) {
            logger.debug("没有解析到用户ID");
        } else {
            logger.debug("已存在非匿名认证信息,跳过JWT认证");
        }
 
        filterChain.doFilter(request, response);
    }
}