From 0a48616045ddce1562584543a0e89e5144051fde Mon Sep 17 00:00:00 2001
From: Codex Assistant <codex@example.com>
Date: 星期日, 05 十月 2025 14:52:44 +0800
Subject: [PATCH] 报名审核

---
 backend/src/main/java/com/rongyichuang/auth/filter/JwtAuthenticationFilter.java |  265 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 260 insertions(+), 5 deletions(-)

diff --git a/backend/src/main/java/com/rongyichuang/auth/filter/JwtAuthenticationFilter.java b/backend/src/main/java/com/rongyichuang/auth/filter/JwtAuthenticationFilter.java
index 32c4aa5..c0f9452 100644
--- a/backend/src/main/java/com/rongyichuang/auth/filter/JwtAuthenticationFilter.java
+++ b/backend/src/main/java/com/rongyichuang/auth/filter/JwtAuthenticationFilter.java
@@ -10,16 +10,22 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
 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 org.springframework.web.util.ContentCachingRequestWrapper;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Optional;
 
 /**
@@ -35,35 +41,276 @@
 
     @Autowired
     private UserRepository userRepository;
+    
+    // 鍏佽鍖垮悕璁块棶鐨凣raphQL鏌ヨ鍒楄〃
+    private static final List<String> PUBLIC_GRAPHQL_QUERIES = Arrays.asList(
+        "carouselPlayList",
+        "activities",
+        "hello"
+    );
+    
+    /**
+     * 鍒ゆ柇鏄惁搴旇璺宠繃JWT璁よ瘉
+     */
+    private boolean shouldSkipAuthentication(String requestURI) {
+        // 杩欎簺璺緞涓嶉渶瑕丣WT璁よ瘉锛堝凡鍘绘帀context path锛�
+        String[] skipPaths = {
+            "/auth/",
+            "/actuator/",
+            "/test/",
+            "/cleanup/",
+            "/upload/",
+            "/graphiql"   // GraphiQL寮�鍙戝伐鍏�
+            // 娉ㄦ剰锛�/graphql 涓嶅湪璺宠繃鍒楄〃涓紝闇�瑕佺敱JWT杩囨护鍣ㄥ鐞嗕互鍖哄垎鍏紑鍜岀鏈夋煡璇�
+        };
+        
+        for (String path : skipPaths) {
+            if (requestURI.startsWith(path)) {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    /**
+     * 妫�鏌ユ槸鍚︽槸GraphQL璇锋眰
+     */
+    private boolean isGraphQLRequest(String requestURI) {
+        return "/graphql".equals(requestURI);
+    }
+    
+    /**
+     * 妫�鏌raphQL璇锋眰鏄惁涓哄叕寮�鏌ヨ锛堜笉闇�瑕佽璇侊級
+     * 鍙湁鏄庣‘鏍囪涓哄叕寮�鐨勬煡璇㈡墠鍏佽鍖垮悕璁块棶
+     */
+    private boolean isPublicGraphQLQuery(HttpServletRequest request) {
+        try {
+            // 妫�鏌ET鍙傛暟涓殑query
+            String query = request.getParameter("query");
+            if (query != null && !query.trim().isEmpty()) {
+                logger.debug("浠庡弬鏁拌幏鍙朑raphQL鏌ヨ: {}", query);
+                return containsPublicQuery(query);
+            }
+            
+            // 瀵逛簬POST璇锋眰锛屽皾璇曡鍙栬姹備綋
+            if ("POST".equalsIgnoreCase(request.getMethod())) {
+                try {
+                    // 浣跨敤CachedBodyHttpServletRequest鏉ヨ鍙栬姹備綋
+                    String body = getRequestBody(request);
+                    if (body != null && !body.trim().isEmpty()) {
+                        logger.debug("浠庤姹備綋鑾峰彇GraphQL鏌ヨ: {}", body);
+                        
+                        // 妫�鏌ontent-Type
+                        String contentType = request.getContentType();
+                        if (contentType != null && contentType.contains("application/graphql")) {
+                            // 瀵逛簬application/graphql锛岃姹備綋鐩存帴鏄疓raphQL鏌ヨ
+                            return containsPublicQuery(body);
+                        } else {
+                            // 瀵逛簬application/json锛岀畝鍗曡В鏋怞SON锛屾煡鎵緌uery瀛楁
+                            if (body.contains("\"query\"")) {
+                                return containsPublicQuery(body);
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    logger.warn("璇诲彇POST璇锋眰浣撳け璐�", e);
+                }
+            }
+            
+            return false;
+        } catch (Exception e) {
+            logger.error("瑙f瀽GraphQL璇锋眰澶辫触", e);
+            return false;
+        }
+    }
+    
+    /**
+     * 璇诲彇璇锋眰浣撳唴瀹�
+     */
+    private String getRequestBody(HttpServletRequest request) {
+        try {
+            if (request instanceof ContentCachingRequestWrapper) {
+                ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
+                byte[] content = wrapper.getContentAsByteArray();
+                if (content.length > 0) {
+                    String encoding = wrapper.getCharacterEncoding() != null ? wrapper.getCharacterEncoding() : "UTF-8";
+                    return new String(content, encoding);
+                }
+            }
+            // 涓嶄粠鍘熷璇锋眰娴佽鍙栵紝閬垮厤涓嬫父缁勪欢鎷夸笉鍒拌姹備綋瀵艰嚧 400
+            return null;
+        } catch (Exception e) {
+            logger.warn("璇诲彇璇锋眰浣撳け璐�", e);
+            return null;
+        }
+    }
+    
+    /**
+     * 妫�鏌ユ煡璇㈠瓧绗︿覆鏄惁鍖呭惈鍏紑鏌ヨ
+     */
+    private boolean containsPublicQuery(String queryString) {
+        if (queryString == null || queryString.trim().isEmpty()) {
+            return false;
+        }
+        
+        // 妫�鏌ユ槸鍚﹀寘鍚叕寮�鏌ヨ
+        for (String publicQuery : PUBLIC_GRAPHQL_QUERIES) {
+            if (queryString.contains(publicQuery)) {
+                logger.debug("妫�娴嬪埌鍏紑GraphQL鏌ヨ: {}", publicQuery);
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    /**
+     * 杩斿洖鏉冮檺閿欒鍝嶅簲
+     */
+    private void sendUnauthorizedResponse(HttpServletResponse response) throws IOException {
+        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        response.setContentType("application/json;charset=UTF-8");
+        response.getWriter().write("{\"errors\":[{\"message\":\"娌℃湁鏉冮檺璁块棶锛岃鍏堢櫥褰昞",\"extensions\":{\"code\":\"UNAUTHORIZED\"}}]}");
+    }
 
     @Override
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, 
-                                  FilterChain filterChain) throws ServletException, IOException {
+                                    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;
+        }
+        
+        // 瀵笹raphQL璇锋眰杩涜鐗规畩澶勭悊
+        if (isGraphQLRequest(pathWithoutContext)) {
+            logger.debug("妫�娴嬪埌GraphQL璇锋眰");
+            
+            // 涓篜OST璇锋眰鍖呰璇锋眰浠ユ敮鎸侀噸澶嶈鍙栬姹備綋
+            HttpServletRequest wrappedRequest = request;
+            if ("POST".equalsIgnoreCase(request.getMethod())) {
+                wrappedRequest = new ContentCachingRequestWrapper(request);
+            }
+            
+            // 鍏堟鏌uthorization澶达紝濡傛灉娌℃湁token锛屽啀妫�鏌ユ槸鍚︿负鍏紑鏌ヨ
+            String authHeader = request.getHeader("Authorization");
+            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
+                logger.debug("GraphQL璇锋眰娌℃湁Authorization澶达紝灏濊瘯鍒ゅ畾鏄惁涓哄叕寮�鏌ヨ");
+                
+                // 灏濊瘯鍒ゅ畾鍏紑鏌ヨ锛涘鏋滆兘纭畾鏄叕寮�鏌ヨ鍒欐斁琛�
+                if (isPublicGraphQLQuery(wrappedRequest)) {
+                    logger.debug("妫�娴嬪埌鍏紑GraphQL鏌ヨ锛屽厑璁稿尶鍚嶈闂�");
+                    AnonymousAuthenticationToken anonymousAuth = new AnonymousAuthenticationToken(
+                        "anonymous",
+                        "anonymous",
+                        Arrays.asList(new SimpleGrantedAuthority("ROLE_ANONYMOUS"))
+                    );
+                    SecurityContextHolder.getContext().setAuthentication(anonymousAuth);
+                    filterChain.doFilter(wrappedRequest, response);
+                    return;
+                }
+                
+                // 鏃犳硶鍙潬璇诲彇/鍒ゅ畾璇锋眰浣撴椂锛岄粯璁や互鍖垮悕韬唤鏀捐鍒癎raphQL灞傦紝鐢卞悇Resolver鑷杩涜鏉冮檺鏍¢獙
+                logger.debug("鏃犳硶鍙潬鍒ゅ畾鏄惁涓哄叕寮�鏌ヨ锛岃缃尶鍚嶈璇佸苟浜ょ敱GraphQL灞傚鐞�");
+                AnonymousAuthenticationToken anonymousAuth = new AnonymousAuthenticationToken(
+                    "anonymous",
+                    "anonymous",
+                    Arrays.asList(new SimpleGrantedAuthority("ROLE_ANONYMOUS"))
+                );
+                SecurityContextHolder.getContext().setAuthentication(anonymousAuth);
+                filterChain.doFilter(wrappedRequest, response);
+                return;
+            }
+            
+            logger.debug("妫�娴嬪埌闇�瑕佽璇佺殑GraphQL璇锋眰锛屽紑濮嬮獙璇丣WT");
+            
+            String token = authHeader.substring(7);
+            try {
+                Long userId = jwtUtil.getUserIdFromToken(token);
+                if (userId == null || !jwtUtil.validateToken(token)) {
+                    logger.warn("GraphQL璇锋眰鐨凧WT token鏃犳晥");
+                    sendUnauthorizedResponse(response);
+                    return;
+                }
+                
+                // 鏌ユ壘鐢ㄦ埛淇℃伅骞惰缃璇�
+                Optional<User> userOpt = userRepository.findById(userId);
+                if (userOpt.isPresent()) {
+                    User user = userOpt.get();
+                    UsernamePasswordAuthenticationToken authToken = 
+                        new UsernamePasswordAuthenticationToken(
+                            user.getId().toString(), 
+                            null, 
+                            new ArrayList<>()
+                        );
+                    authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+                    SecurityContextHolder.getContext().setAuthentication(authToken);
+                    logger.debug("GraphQL璇锋眰璁よ瘉鎴愬姛: userId={}", user.getId());
+                } else {
+                    logger.warn("GraphQL璇锋眰鐨勭敤鎴蜂笉瀛樺湪: userId={}", userId);
+                    sendUnauthorizedResponse(response);
+                    return;
+                }
+            } catch (Exception e) {
+                logger.error("GraphQL璇锋眰JWT楠岃瘉澶辫触: {}", e.getMessage());
+                sendUnauthorizedResponse(response);
+                return;
+            }
+            
+            // 缁х画澶勭悊璇锋眰
+            filterChain.doFilter(wrappedRequest, response);
+            return;
+        }
         
         String authHeader = request.getHeader("Authorization");
         String token = null;
         Long userId = null;
 
+        logger.debug("Authorization澶�: {}", authHeader);
+
         // 浠庤姹傚ご涓彁鍙朖WT token
         if (authHeader != null && authHeader.startsWith("Bearer ")) {
             token = authHeader.substring(7);
+            logger.debug("鎻愬彇鍒癑WT token: {}", token.substring(0, Math.min(20, token.length())) + "...");
             try {
                 userId = jwtUtil.getUserIdFromToken(token);
+                logger.debug("浠巘oken涓В鏋愬埌鐢ㄦ埛ID: {}", userId);
             } catch (Exception e) {
-                logger.debug("JWT token瑙f瀽澶辫触: {}", e.getMessage());
+                logger.error("JWT token瑙f瀽澶辫触: {}", e.getMessage(), e);
             }
+        } else {
+            logger.debug("娌℃湁鎵惧埌Authorization澶存垨鏍煎紡涓嶆纭�");
         }
 
-        // 濡傛灉token鏈夋晥涓斿綋鍓嶆病鏈夎璇佷俊鎭�
-        if (userId != null && SecurityContextHolder.getContext().getAuthentication() == null) {
+        // 濡傛灉token鏈夋晥涓斿綋鍓嶆槸鍖垮悕鎴栨棤璁よ瘉锛屽垯杩涜璁よ瘉
+        Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
+        boolean isAnonymous = (existingAuth == null) || ("anonymousUser".equals(String.valueOf(existingAuth.getPrincipal())));
+        if (userId != null && isAnonymous) {
+            logger.debug("寮�濮嬮獙璇乼oken鏈夋晥鎬�");
             
             // 楠岃瘉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 = 
@@ -76,9 +323,17 @@
                     authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                     SecurityContextHolder.getContext().setAuthentication(authToken);
                     
-                    logger.debug("鐢ㄦ埛璁よ瘉鎴愬姛: userId={}, phone={}", user.getId(), user.getPhone());
+                    logger.info("鐢ㄦ埛璁よ瘉鎴愬姛: userId={}, phone={}", user.getId(), user.getPhone());
+                } else {
+                    logger.warn("鐢ㄦ埛涓嶅瓨鍦�: userId={}", userId);
                 }
+            } else {
+                logger.warn("Token楠岃瘉澶辫触");
             }
+        } else if (userId == null) {
+            logger.debug("娌℃湁瑙f瀽鍒扮敤鎴稩D");
+        } else {
+            logger.debug("宸插瓨鍦ㄩ潪鍖垮悕璁よ瘉淇℃伅锛岃烦杩嘕WT璁よ瘉");
         }
 
         filterChain.doFilter(request, response);

--
Gitblit v1.8.0