From 8d74746091b3ef74fcb4496e47058ea75dd6fece Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Mon, 18 Aug 2025 21:52:56 +0900 Subject: [PATCH 1/5] =?UTF-8?q?refactor:=20=EC=9B=B9=EC=86=8C=EC=BC=93=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=20=EC=9A=94=EC=B2=AD=EC=9D=80=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=86=A0=ED=81=B0=EC=9D=84=20=EC=9D=BD=EB=8F=84?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/filter/TokenAuthenticationFilter.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java b/src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java index 0a81b860e..74222f7aa 100644 --- a/src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java +++ b/src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java @@ -28,7 +28,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { public void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException { - Optional token = authorizationHeaderParser.parseToken(request); + Optional token = resolveToken(request); if (token.isEmpty()) { filterChain.doFilter(request, response); return; @@ -40,4 +40,11 @@ public void doFilterInternal(@NonNull HttpServletRequest request, filterChain.doFilter(request, response); } + + private Optional resolveToken(HttpServletRequest request) { + if (request.getRequestURI().startsWith("/connect")) { + return Optional.ofNullable(request.getParameter("token")); + } + return authorizationHeaderParser.parseToken(request); + } } From f5940a69cc205a9da9852e06de403ffc6f09428f Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Mon, 18 Aug 2025 21:55:25 +0900 Subject: [PATCH 2/5] =?UTF-8?q?refactor:=20=EC=9D=B8=ED=84=B0=EC=85=89?= =?UTF-8?q?=ED=84=B0=EA=B0=80=20=EC=9D=B8=EC=A6=9D=EC=97=90=20=EA=B4=80?= =?UTF-8?q?=EC=97=AC=ED=95=98=EB=8D=98=20=EB=A1=9C=EC=A7=81=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 인터셉터는 인증된 Principal 객체를 세션에 담는데 집중한다. - 토큰 필터가 인증 작업을 처리한다. --- .../chat/config/WebSocketHandshakeInterceptor.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/example/solidconnection/chat/config/WebSocketHandshakeInterceptor.java b/src/main/java/com/example/solidconnection/chat/config/WebSocketHandshakeInterceptor.java index 9e8aafe2d..e4af7a412 100644 --- a/src/main/java/com/example/solidconnection/chat/config/WebSocketHandshakeInterceptor.java +++ b/src/main/java/com/example/solidconnection/chat/config/WebSocketHandshakeInterceptor.java @@ -19,10 +19,9 @@ public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse res if (principal != null) { attributes.put("user", principal); - return true; } - return false; + return true; } @Override From 8e92929634468ef5da9c2565bbea070697a8cdd0 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Mon, 18 Aug 2025 22:16:30 +0900 Subject: [PATCH 3/5] =?UTF-8?q?test:=20=EB=B3=80=EA=B2=BD=EB=90=9C=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WebSocketStompIntegrationTest.java | 46 +++++-------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/src/test/java/com/example/solidconnection/websocket/WebSocketStompIntegrationTest.java b/src/test/java/com/example/solidconnection/websocket/WebSocketStompIntegrationTest.java index 978bfd717..56bf183cf 100644 --- a/src/test/java/com/example/solidconnection/websocket/WebSocketStompIntegrationTest.java +++ b/src/test/java/com/example/solidconnection/websocket/WebSocketStompIntegrationTest.java @@ -2,8 +2,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.ThrowableAssert.catchThrowable; -import static org.junit.jupiter.api.Assertions.assertAll; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.example.solidconnection.auth.service.AccessToken; import com.example.solidconnection.auth.service.AuthTokenProvider; @@ -11,9 +10,8 @@ import com.example.solidconnection.siteuser.fixture.SiteUserFixture; import com.example.solidconnection.support.TestContainerSpringBootTest; import java.util.List; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -22,11 +20,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.messaging.converter.MappingJackson2MessageConverter; -import org.springframework.messaging.simp.stomp.StompHeaders; import org.springframework.messaging.simp.stomp.StompSession; import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter; import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.socket.WebSocketHttpHeaders; import org.springframework.web.socket.client.standard.StandardWebSocketClient; import org.springframework.web.socket.messaging.WebSocketStompClient; import org.springframework.web.socket.sockjs.client.SockJsClient; @@ -67,48 +63,28 @@ void tearDown() { @Nested class WebSocket_핸드셰이크_및_STOMP_세션_수립_테스트 { - private final BlockingQueue transportErrorQueue = new ArrayBlockingQueue<>(1); - - private final StompSessionHandlerAdapter sessionHandler = new StompSessionHandlerAdapter() { - @Override - public void handleTransportError(StompSession session, Throwable exception) { - transportErrorQueue.add(exception); - } - }; - @Test void 인증된_사용자는_핸드셰이크를_성공한다() throws Exception { // given SiteUser user = siteUserFixture.사용자(); AccessToken accessToken = authTokenProvider.generateAccessToken(user); - - WebSocketHttpHeaders handshakeHeaders = new WebSocketHttpHeaders(); - handshakeHeaders.add("Authorization", "Bearer " + accessToken.token()); + String tokenUrl = url + "?token=" + accessToken.token(); // when - stompSession = stompClient.connectAsync(url, handshakeHeaders, new StompHeaders(), sessionHandler).get(5, SECONDS); + stompSession = stompClient.connectAsync(tokenUrl, new StompSessionHandlerAdapter() {}).get(5, SECONDS); // then - assertAll( - () -> assertThat(stompSession).isNotNull(), - () -> assertThat(transportErrorQueue).isEmpty() - ); + assertThat(stompSession.isConnected()).isTrue(); } @Test void 인증되지_않은_사용자는_핸드셰이크를_실패한다() { - // when - Throwable thrown = catchThrowable(() -> { - stompSession = stompClient.connectAsync(url, new WebSocketHttpHeaders(), new StompHeaders(), sessionHandler).get(5, SECONDS); - }); - - // then - assertAll( - () -> assertThat(thrown) - .isInstanceOf(ExecutionException.class) - .hasCauseInstanceOf(HttpClientErrorException.Unauthorized.class), - () -> assertThat(transportErrorQueue).hasSize(1) - ); + // when & then + assertThatThrownBy(() -> { + stompClient.connectAsync(url, new StompSessionHandlerAdapter() { + }).get(5, TimeUnit.SECONDS); + }).isInstanceOf(ExecutionException.class) + .hasCauseInstanceOf(HttpClientErrorException.Unauthorized.class); } } } From db84b003cc29b1b3eb90fb7d02dfa6cdb5c9dd10 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Wed, 20 Aug 2025 08:14:33 +0900 Subject: [PATCH 4/5] =?UTF-8?q?refactor:=20=EB=B9=88=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=EC=9D=80=20=ED=86=A0=ED=81=B0=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EA=B0=84=EC=A3=BC=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94?= =?UTF-8?q?=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/filter/TokenAuthenticationFilter.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java b/src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java index 74222f7aa..8c8dc8f30 100644 --- a/src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java +++ b/src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java @@ -28,15 +28,13 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { public void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException { - Optional token = resolveToken(request); - if (token.isEmpty()) { - filterChain.doFilter(request, response); - return; - } + Optional resolvedToken = resolveToken(request); - TokenAuthentication authToken = new TokenAuthentication(token.get()); - Authentication auth = authenticationManager.authenticate(authToken); - SecurityContextHolder.getContext().setAuthentication(auth); + resolvedToken.filter(token -> !token.isBlank()).ifPresent(token -> { + TokenAuthentication authToken = new TokenAuthentication(token); + Authentication auth = authenticationManager.authenticate(authToken); + SecurityContextHolder.getContext().setAuthentication(auth); + }); filterChain.doFilter(request, response); } From ffac4910a4e53dd5734b6e90bb03744922174ca3 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Wed, 20 Aug 2025 13:34:39 +0900 Subject: [PATCH 5/5] =?UTF-8?q?chore:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websocket/WebSocketStompIntegrationTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/example/solidconnection/websocket/WebSocketStompIntegrationTest.java b/src/test/java/com/example/solidconnection/websocket/WebSocketStompIntegrationTest.java index 56bf183cf..b39c91ece 100644 --- a/src/test/java/com/example/solidconnection/websocket/WebSocketStompIntegrationTest.java +++ b/src/test/java/com/example/solidconnection/websocket/WebSocketStompIntegrationTest.java @@ -71,7 +71,8 @@ class WebSocket_핸드셰이크_및_STOMP_세션_수립_테스트 { String tokenUrl = url + "?token=" + accessToken.token(); // when - stompSession = stompClient.connectAsync(tokenUrl, new StompSessionHandlerAdapter() {}).get(5, SECONDS); + stompSession = stompClient.connectAsync(tokenUrl, new StompSessionHandlerAdapter() { + }).get(5, SECONDS); // then assertThat(stompSession.isConnected()).isTrue();