diff --git a/src/main/java/B1G4/bookmark/apiPayload/exception/handler/StompHandler.java b/src/main/java/B1G4/bookmark/apiPayload/exception/handler/StompHandler.java index 2d8ea73..3e93c3b 100644 --- a/src/main/java/B1G4/bookmark/apiPayload/exception/handler/StompHandler.java +++ b/src/main/java/B1G4/bookmark/apiPayload/exception/handler/StompHandler.java @@ -7,6 +7,9 @@ import org.springframework.messaging.simp.stomp.StompCommand; import org.springframework.messaging.simp.stomp.StompHeaderAccessor; import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import java.util.Objects; @@ -14,13 +17,38 @@ @Component @RequiredArgsConstructor public class StompHandler implements ChannelInterceptor { + private final JwtTokenProvider jwtTokenProvider; @Override public Message preSend(Message message, MessageChannel channel) { StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message); + if (StompCommand.CONNECT.equals(accessor.getCommand())) { - jwtTokenProvider.validateToken(Objects.requireNonNull(accessor.getFirstNativeHeader("Authorization")).substring(7)); + // 헤더에서 JWT 추출 + String token = accessor.getFirstNativeHeader("Authorization"); + + + if (Objects.nonNull(token) && token.startsWith("Bearer ")) { + token = token.substring(7); // Bearer 부분을 제거 + + try { + // JWT 인증 수행 + Authentication authentication = jwtTokenProvider.getAuthentication(token); + + // StompAccessor에 사용자 정보를 추가 (STOMP 메시지 사용자 정보) + accessor.setUser(authentication); + + // **SecurityContext에 인증 정보를 추가 (Spring Security에 인증 정보 추가)** + SecurityContext context = SecurityContextHolder.createEmptyContext(); + context.setAuthentication(authentication); + SecurityContextHolder.setContext(context); + + + } catch (Exception e) { + } + } else { + } } return message; } diff --git a/src/main/java/B1G4/bookmark/config/WebSocketConfig.java b/src/main/java/B1G4/bookmark/config/WebSocketConfig.java index 356701e..bb9d743 100644 --- a/src/main/java/B1G4/bookmark/config/WebSocketConfig.java +++ b/src/main/java/B1G4/bookmark/config/WebSocketConfig.java @@ -42,29 +42,7 @@ public void registerStompEndpoints(StompEndpointRegistry registry) { @Override public void configureClientInboundChannel(ChannelRegistration registration) { - registration.interceptors(new ChannelInterceptor() { - @Override - public Message preSend(Message message, MessageChannel channel) { - StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message); - - if (StompCommand.CONNECT.equals(accessor.getCommand()) || - StompCommand.SUBSCRIBE.equals(accessor.getCommand()) || - StompCommand.SEND.equals(accessor.getCommand())) { - - String token = accessor.getFirstNativeHeader("Authorization"); - if (Objects.nonNull(token) && token.startsWith("Bearer ")) { - token = token.substring(7); // "Bearer " 제거 - try { - Authentication authentication = jwtTokenProvider.getAuthentication(token); - accessor.setUser(authentication); // 사용자 정보 추가 - } catch (Exception e) { - System.out.println("WebSocket Authentication failed: " + e.getMessage()); - } - } - } - return message; - } - }); + registration.interceptors(stompHandler); // StompHandler 추가 } } diff --git a/src/main/java/B1G4/bookmark/security/provider/JwtTokenProvider.java b/src/main/java/B1G4/bookmark/security/provider/JwtTokenProvider.java index 59aed76..3b774f8 100644 --- a/src/main/java/B1G4/bookmark/security/provider/JwtTokenProvider.java +++ b/src/main/java/B1G4/bookmark/security/provider/JwtTokenProvider.java @@ -90,13 +90,15 @@ private Jws getClaims(String token) { } public Authentication getAuthentication(String token) { - try { - Long memberId = getId(token); // Extract member ID from JWT - User principal = new User(memberId.toString(), "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))); - return new UsernamePasswordAuthenticationToken(principal, token, principal.getAuthorities()); - } catch (Exception e) { - throw new AuthException(ErrorStatus.AUTH_INVALID_TOKEN); - } + Claims claims = Jwts.parserBuilder() + .setSigningKey(secretKey) + .build() + .parseClaimsJws(token) + .getBody(); + + String userId = claims.get("id", String.class); + User user = new User(userId, "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))); + return new UsernamePasswordAuthenticationToken(user, token, user.getAuthorities()); } public void validateToken(String token) { diff --git a/src/main/java/B1G4/bookmark/web/controller/ChatController.java b/src/main/java/B1G4/bookmark/web/controller/ChatController.java index 5d50358..515ccac 100644 --- a/src/main/java/B1G4/bookmark/web/controller/ChatController.java +++ b/src/main/java/B1G4/bookmark/web/controller/ChatController.java @@ -22,47 +22,6 @@ public class ChatController { private final ChatRoomServiceImpl chatRoomService; - - // Swagger용 가짜 채팅방 입장 API - @Operation( - summary = "채팅방 입장", - description = "사용자가 특정 채팅방에 입장합니다. 이 경로는 WebSocket 동작을 설명하기 위해 추가된 가짜 API입니다." + - "클라이언트는 /app/chat/{chatRoomId}/join으로 메시지를 발행합니다. "+ - "서버는 /topic/chat/{chatRoomId}로 구독 중인 모든 클라이언트에게 메시지를 브로드캐스트합니다." - ) - @PostMapping("/swagger/chat/{chatRoomId}/join") - public BaseResponse joinChatRoomSwagger( - @DestinationVariable @Parameter( - description = "입장할 채팅방의 ID" + "채팅방 ID는 공간 ID와 같습니다", - required = true - ) Long chatRoomId, - @Parameter(name = "user", hidden = true) - @AuthUser Member member) { - ChatMessageDTO result = chatRoomService.handleJoinChatRoom(chatRoomId, member.getId()); - return BaseResponse.onSuccess(result); - } - - // Swagger용 가짜 메시지 전송 API - @Operation( - summary = "메시지 전송", - description = "사용자가 특정 채팅방에 메시지를 전송합니다. 이 경로는 WebSocket 동작을 설명하기 위해 추가된 가짜 API입니다." + - "클라이언트는 /app/chat/{chatRoomId}/send로 메시지를 발행합니다." + - "서버는 /topic/chat/{chatRoomId}로 구독 중인 모든 클라이언트에게 메시지를 브로드캐스트합니다." - - ) - @PostMapping("/swagger/chat/{chatRoomId}/send") - public BaseResponse sendMessageSwagger( - @DestinationVariable @Parameter( - description = "메시지를 전송할 채팅방의 ID" + "채팅방 ID는 공간ID와 같습니다", - required = true - ) Long chatRoomId, - @RequestBody @Parameter( - description = "전송할 메시지의 정보", - required = true - ) ChatMessageDTO messageDTO) { - return BaseResponse.onSuccess(chatRoomService.handleSendMessage(chatRoomId, messageDTO)); - } - // 채팅방 입장 /** * 채팅방 입장