diff --git a/gym-manage-api/manage-gateway/src/main/java/cn/novalon/gym/manage/gateway/filter/JwtAuthenticationFilter.java b/gym-manage-api/manage-gateway/src/main/java/cn/novalon/gym/manage/gateway/filter/JwtAuthenticationFilter.java index 54c4a4e..07754f0 100644 --- a/gym-manage-api/manage-gateway/src/main/java/cn/novalon/gym/manage/gateway/filter/JwtAuthenticationFilter.java +++ b/gym-manage-api/manage-gateway/src/main/java/cn/novalon/gym/manage/gateway/filter/JwtAuthenticationFilter.java @@ -42,6 +42,13 @@ public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory result = filter.apply(new JwtAuthenticationFilter.Config()) + .filter(exchange, chain); + + StepVerifier.create(result) + .verifyComplete(); + + verify(chain).filter(any(ServerWebExchange.class)); + verify(jwtUtil, never()).validateToken(anyString()); + } + + @Test + void testPublicPath_CheckIn() { + MockServerHttpRequest request = MockServerHttpRequest.post("/api/checkIn/").build(); + exchange = MockServerWebExchange.from(request); + + when(chain.filter(any(ServerWebExchange.class))).thenReturn(Mono.empty()); + + Mono result = filter.apply(new JwtAuthenticationFilter.Config()) + .filter(exchange, chain); + + StepVerifier.create(result) + .verifyComplete(); + + verify(chain).filter(any(ServerWebExchange.class)); + verify(jwtUtil, never()).validateToken(anyString()); + } + @Test void testProtectedPath_NoAuthHeader() { MockServerHttpRequest request = MockServerHttpRequest.get("/api/users").build(); @@ -152,6 +186,7 @@ class GatewayJwtAuthenticationFilterTest { when(jwtUtil.isTokenExpired(validToken)).thenReturn(false); when(jwtUtil.getUsernameFromToken(validToken)).thenReturn("testuser"); when(jwtUtil.getUserIdFromToken(validToken)).thenReturn(1L); + when(jwtUtil.getUserTypeFromToken(validToken)).thenReturn("ADMIN"); Mono result = filter.apply(new JwtAuthenticationFilter.Config()) .filter(exchange, chain); @@ -163,6 +198,7 @@ class GatewayJwtAuthenticationFilterTest { verify(jwtUtil).isTokenExpired(validToken); verify(jwtUtil).getUsernameFromToken(validToken); verify(jwtUtil).getUserIdFromToken(validToken); + verify(jwtUtil).getUserTypeFromToken(validToken); verify(chain).filter(any(ServerWebExchange.class)); } @@ -224,6 +260,7 @@ class GatewayJwtAuthenticationFilterTest { when(jwtUtil.isTokenExpired(validToken)).thenReturn(false); when(jwtUtil.getUsernameFromToken(validToken)).thenReturn("testuser"); when(jwtUtil.getUserIdFromToken(validToken)).thenReturn(1L); + when(jwtUtil.getUserTypeFromToken(validToken)).thenReturn("ADMIN"); Mono result = filter.apply(new JwtAuthenticationFilter.Config()) .filter(exchange, chain); @@ -235,6 +272,7 @@ class GatewayJwtAuthenticationFilterTest { verify(jwtUtil).isTokenExpired(validToken); verify(jwtUtil).getUsernameFromToken(validToken); verify(jwtUtil).getUserIdFromToken(validToken); + verify(jwtUtil).getUserTypeFromToken(validToken); verify(chain).filter(any(ServerWebExchange.class)); } @@ -251,6 +289,7 @@ class GatewayJwtAuthenticationFilterTest { when(jwtUtil.isTokenExpired(validToken)).thenReturn(false); when(jwtUtil.getUsernameFromToken(validToken)).thenReturn("testuser"); when(jwtUtil.getUserIdFromToken(validToken)).thenReturn(1L); + when(jwtUtil.getUserTypeFromToken(validToken)).thenReturn("ADMIN"); Mono result = filter.apply(new JwtAuthenticationFilter.Config()) .filter(exchange, chain); @@ -263,6 +302,7 @@ class GatewayJwtAuthenticationFilterTest { ServerHttpRequest modifiedRequest = exchangeCaptor.getValue().getRequest(); assert modifiedRequest.getHeaders().getFirst("X-User-Id").equals("1"); assert modifiedRequest.getHeaders().getFirst("X-Username").equals("testuser"); + assert modifiedRequest.getHeaders().getFirst("X-User-Type").equals("ADMIN"); } @Test @@ -295,6 +335,7 @@ class GatewayJwtAuthenticationFilterTest { when(jwtUtil.isTokenExpired(validToken)).thenReturn(false); when(jwtUtil.getUsernameFromToken(validToken)).thenReturn("testuser"); when(jwtUtil.getUserIdFromToken(validToken)).thenReturn(1L); + when(jwtUtil.getUserTypeFromToken(validToken)).thenReturn("ADMIN"); Mono result = filter.apply(new JwtAuthenticationFilter.Config()) .filter(exchange, chain); @@ -308,4 +349,123 @@ class GatewayJwtAuthenticationFilterTest { verify(jwtUtil).getUserIdFromToken(validToken); verify(chain).filter(any(ServerWebExchange.class)); } + + // ========== userType 路径校验测试 ========== + + @Test + void testAdminPath_WithAdminToken_ShouldPass() { + String adminToken = "admin.jwt.token"; + MockServerHttpRequest request = MockServerHttpRequest.get("/api/admin/users") + .header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken) + .build(); + exchange = MockServerWebExchange.from(request); + + when(chain.filter(any(ServerWebExchange.class))).thenReturn(Mono.empty()); + when(jwtUtil.validateToken(adminToken)).thenReturn(true); + when(jwtUtil.isTokenExpired(adminToken)).thenReturn(false); + when(jwtUtil.getUsernameFromToken(adminToken)).thenReturn("admin"); + when(jwtUtil.getUserIdFromToken(adminToken)).thenReturn(1L); + when(jwtUtil.getUserTypeFromToken(adminToken)).thenReturn("ADMIN"); + + Mono result = filter.apply(new JwtAuthenticationFilter.Config()) + .filter(exchange, chain); + + StepVerifier.create(result) + .verifyComplete(); + + verify(chain).filter(any(ServerWebExchange.class)); + } + + @Test + void testAdminPath_WithMemberToken_ShouldBeForbidden() { + String memberToken = "member.jwt.token"; + MockServerHttpRequest request = MockServerHttpRequest.get("/api/admin/users") + .header(HttpHeaders.AUTHORIZATION, "Bearer " + memberToken) + .build(); + exchange = MockServerWebExchange.from(request); + + when(jwtUtil.validateToken(memberToken)).thenReturn(true); + when(jwtUtil.isTokenExpired(memberToken)).thenReturn(false); + when(jwtUtil.getUserTypeFromToken(memberToken)).thenReturn("MEMBER"); + + Mono result = filter.apply(new JwtAuthenticationFilter.Config()) + .filter(exchange, chain); + + StepVerifier.create(result) + .verifyComplete(); + + assert exchange.getResponse().getStatusCode() == HttpStatus.FORBIDDEN; + verify(chain, never()).filter(any(ServerWebExchange.class)); + } + + @Test + void testMemberPath_WithMemberToken_ShouldPass() { + String memberToken = "member.jwt.token"; + MockServerHttpRequest request = MockServerHttpRequest.get("/api/member/info") + .header(HttpHeaders.AUTHORIZATION, "Bearer " + memberToken) + .build(); + exchange = MockServerWebExchange.from(request); + + when(chain.filter(any(ServerWebExchange.class))).thenReturn(Mono.empty()); + when(jwtUtil.validateToken(memberToken)).thenReturn(true); + when(jwtUtil.isTokenExpired(memberToken)).thenReturn(false); + when(jwtUtil.getUsernameFromToken(memberToken)).thenReturn("123"); + when(jwtUtil.getUserIdFromToken(memberToken)).thenReturn(123L); + when(jwtUtil.getUserTypeFromToken(memberToken)).thenReturn("MEMBER"); + + Mono result = filter.apply(new JwtAuthenticationFilter.Config()) + .filter(exchange, chain); + + StepVerifier.create(result) + .verifyComplete(); + + verify(chain).filter(any(ServerWebExchange.class)); + } + + @Test + void testMemberPath_WithAdminToken_ShouldBeForbidden() { + String adminToken = "admin.jwt.token"; + MockServerHttpRequest request = MockServerHttpRequest.get("/api/member/info") + .header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken) + .build(); + exchange = MockServerWebExchange.from(request); + + when(jwtUtil.validateToken(adminToken)).thenReturn(true); + when(jwtUtil.isTokenExpired(adminToken)).thenReturn(false); + when(jwtUtil.getUserTypeFromToken(adminToken)).thenReturn("ADMIN"); + + Mono result = filter.apply(new JwtAuthenticationFilter.Config()) + .filter(exchange, chain); + + StepVerifier.create(result) + .verifyComplete(); + + assert exchange.getResponse().getStatusCode() == HttpStatus.FORBIDDEN; + verify(chain, never()).filter(any(ServerWebExchange.class)); + } + + @Test + void testNonPrefixedPath_NoUserTypeCheck() { + String adminToken = "admin.jwt.token"; + // /api/users 不以 /api/admin/ 或 /api/member/ 开头,不做 userType 校验 + MockServerHttpRequest request = MockServerHttpRequest.get("/api/users") + .header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken) + .build(); + exchange = MockServerWebExchange.from(request); + + when(chain.filter(any(ServerWebExchange.class))).thenReturn(Mono.empty()); + when(jwtUtil.validateToken(adminToken)).thenReturn(true); + when(jwtUtil.isTokenExpired(adminToken)).thenReturn(false); + when(jwtUtil.getUsernameFromToken(adminToken)).thenReturn("admin"); + when(jwtUtil.getUserIdFromToken(adminToken)).thenReturn(1L); + when(jwtUtil.getUserTypeFromToken(adminToken)).thenReturn("ADMIN"); + + Mono result = filter.apply(new JwtAuthenticationFilter.Config()) + .filter(exchange, chain); + + StepVerifier.create(result) + .verifyComplete(); + + verify(chain).filter(any(ServerWebExchange.class)); + } }