diff --git a/src/main/java/com/oronaminc/join/member/security/SecurityConfig.java b/src/main/java/com/oronaminc/join/member/security/SecurityConfig.java index 8332001..42067b2 100644 --- a/src/main/java/com/oronaminc/join/member/security/SecurityConfig.java +++ b/src/main/java/com/oronaminc/join/member/security/SecurityConfig.java @@ -61,7 +61,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowCredentials(true); - configuration.setAllowedOriginPatterns(List.of("*")); + configuration.setAllowedOriginPatterns(List.of("http://localhost:5173")); configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowedHeaders(List.of("*")); diff --git a/src/main/java/com/oronaminc/join/websocket/api/QuestionWebsocketController.java b/src/main/java/com/oronaminc/join/websocket/api/QuestionWebsocketController.java index a0fb291..076eea9 100644 --- a/src/main/java/com/oronaminc/join/websocket/api/QuestionWebsocketController.java +++ b/src/main/java/com/oronaminc/join/websocket/api/QuestionWebsocketController.java @@ -6,12 +6,14 @@ import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.messaging.handler.annotation.SendTo; +import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import com.oronaminc.join.global.exception.ErrorCode; import com.oronaminc.join.global.exception.ErrorException; import com.oronaminc.join.global.ratelimit.RateLimitService; import com.oronaminc.join.global.ratelimit.RateLimitType; +import com.oronaminc.join.member.security.MemberDetails; import com.oronaminc.join.question.domain.Question; import com.oronaminc.join.question.dto.QuestionCreateResponse; import com.oronaminc.join.question.dto.QuestionDeleteResponse; @@ -41,8 +43,10 @@ public QuestionCreateResponse createQuestion( Principal principal ) { log.debug("수신한 메시지 = {}", request.content()); + log.debug("principal = {}", principal); - Long memberId = Long.valueOf(principal.getName()); + MemberDetails memberDetails = (MemberDetails)((Authentication)principal).getPrincipal(); + Long memberId = Long.valueOf(memberDetails.getId()); log.debug("회원 아이디 = {}", memberId); @@ -66,6 +70,7 @@ public QuestionUpdateResponse updateQuestion( @Payload @Valid QuestionRequest request, Principal principal ) { + Long memberId = Long.valueOf(principal.getName()); Question updated = questionService.update(memberId, roomId, questionId, request); diff --git a/src/main/java/com/oronaminc/join/websocket/config/StompAuthChannelInterceptor.java b/src/main/java/com/oronaminc/join/websocket/config/StompAuthChannelInterceptor.java new file mode 100644 index 0000000..0cc944d --- /dev/null +++ b/src/main/java/com/oronaminc/join/websocket/config/StompAuthChannelInterceptor.java @@ -0,0 +1,29 @@ +package com.oronaminc.join.websocket.config; + +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.simp.stomp.StompCommand; +import org.springframework.messaging.simp.stomp.StompHeaderAccessor; +import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.messaging.support.MessageHeaderAccessor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +@Component +public class StompAuthChannelInterceptor implements ChannelInterceptor { + @Override + public Message preSend(Message message, MessageChannel channel) { + StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); + + if (StompCommand.CONNECT.equals(accessor.getCommand())) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication != null && authentication.isAuthenticated()) { + accessor.setUser(authentication); + } + } + + return message; + } +} diff --git a/src/main/java/com/oronaminc/join/websocket/config/WebSocketConfig.java b/src/main/java/com/oronaminc/join/websocket/config/WebSocketConfig.java index 797a0c9..5c8c2ad 100644 --- a/src/main/java/com/oronaminc/join/websocket/config/WebSocketConfig.java +++ b/src/main/java/com/oronaminc/join/websocket/config/WebSocketConfig.java @@ -3,6 +3,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.ChannelRegistration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; @@ -26,6 +27,7 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { private final StompErrorHandler stompErrorHandler; private final WebsocketSessionManager sessionManager; private final ApplicationEventPublisher publisher; + private final StompAuthChannelInterceptor stompAuthChannelInterceptor; @Bean public WebSocketHandlerDecoratorFactory webSocketHandlerDecoratorFactory( @@ -65,4 +67,9 @@ public void registerStompEndpoints(StompEndpointRegistry registry) { public void configureWebSocketTransport(WebSocketTransportRegistration registry) { registry.setDecoratorFactories(webSocketHandlerDecoratorFactory(sessionManager, publisher)); } + + @Override + public void configureClientInboundChannel(ChannelRegistration registration) { + registration.interceptors(stompAuthChannelInterceptor); + } } diff --git a/src/main/java/com/oronaminc/join/websocket/session/CurrentParticipantEventHandler.java b/src/main/java/com/oronaminc/join/websocket/session/CurrentParticipantEventHandler.java index c6b25c2..806c75d 100644 --- a/src/main/java/com/oronaminc/join/websocket/session/CurrentParticipantEventHandler.java +++ b/src/main/java/com/oronaminc/join/websocket/session/CurrentParticipantEventHandler.java @@ -2,14 +2,11 @@ import static com.oronaminc.join.global.exception.ErrorCode.*; -import com.oronaminc.join.global.exception.ErrorCode; import java.security.Principal; import java.util.Set; import org.springframework.context.event.EventListener; -import org.springframework.messaging.simp.stomp.StompHeaderAccessor; import org.springframework.stereotype.Component; -import org.springframework.web.socket.messaging.SessionSubscribeEvent; import com.oronaminc.join.global.exception.ErrorException; import com.oronaminc.join.room.event.RoomExitEvent; @@ -24,27 +21,27 @@ public class CurrentParticipantEventHandler { private static final String ROOM_PREFIX = "/topic/rooms/"; private static final String JOIN_SUFFIX = "/join"; - @EventListener - public void handleSubscribe(SessionSubscribeEvent event) { - StompHeaderAccessor accessor = StompHeaderAccessor.wrap(event.getMessage()); - String destination = accessor.getDestination(); - Principal principal = accessor.getUser(); - - if (destination == null) { - throw new ErrorException(STOMP_INVALID_DESTINATION); - } - - if (!destination.startsWith(ROOM_PREFIX)) { - return; - } - - Long memberId = parseMemberId(principal); - Long roomId = parseRoomId(destination); - - if (!isRoomJoinPath(destination)) { - validateParticipantRoomJoin(roomId, memberId); - } - } + // @EventListener + // public void handleSubscribe(SessionSubscribeEvent event) { + // StompHeaderAccessor accessor = StompHeaderAccessor.wrap(event.getMessage()); + // String destination = accessor.getDestination(); + // Principal principal = accessor.getUser(); + // + // if (destination == null) { + // throw new ErrorException(STOMP_INVALID_DESTINATION); + // } + // + // if (!destination.startsWith(ROOM_PREFIX)) { + // return; + // } + // + // Long memberId = parseMemberId(principal); + // Long roomId = parseRoomId(destination); + // + // if (!isRoomJoinPath(destination)) { + // validateParticipantRoomJoin(roomId, memberId); + // } + // } @EventListener public void handleUnsubscribe(RoomExitEvent event) {