회원기능(인증, 인가) 없이 convertAndSendToUser()를 사용할 때
Principal을 직접 정의하여 사용하는 방법
문제 발생
--
예외처리를 하기 위해
기존 컨트롤러처럼 @SendToUser()를 통해 응답할 수 없는 상황이라서
convertAndSendToUser()를 통해 응답해야 하는 상황이 왔다.
@SendToUser() 같은 경우는 자동으로 Principal을 알아서 사용하여 응답해 주니 값을 몰라도 됐지만
convertAndSendToUser() 같은 경우는 직접 Principal값을 작성해줘야 한다.
하지만 Security를 사용하지 않아서인지 sessionId 또는 user정보를 아무리 사용해도 클라이언트에게 응답이 전달되지 않았다.
그래서 직접 Principal을 정의하기로 했다.
--
Principal 값 설정하기
--
@Component
public class CustomhandshakeHandler extends DefaultHandshakeHandler {
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
String name = UUID.randomUUID().toString();
return new Principal() {
@Override
public String getName() {
return name;
}
};
}
}
웹 소켓 연결 핸드셰이크를 처리하는 기본 구현체인 "DefaultHandshakeHandler"를 확장하여
"CustomhandshakeHandler"로 사용자 정의 로직을 추가한다.
"determineUser"메서드는
웹 소켓 연결 시 자동으로 호출되는 메서드로, Principal() 메서드를 오버라이딩하여 커스텀하기 위해 재정의한다.
- ServerHttpRequest request : 클라이언트의 HTTP 요청 정보
- WebSocketHandler wsHandler : 웹 소켓 처리 담당 핸들러 (웹 소켓 메시지 처리하는 객체)
- Map<String, Object> attributes : 연결 과정에서 추가적인 속성을 저장하거나 참조할 때 사용하는 맵
Principal에 설정할 값을 구하여 name변수에 담는다.
Principal의 getName 메서드를 재정의하여 새로 생성한 name을 사용하도록 재정의한다.
예상 흐름
- 클라이언트가 웹소켓 연결 시도하면 해당 메서드가 호출됨
- UUID를 생성하여 사용자 세션에 대한 고유 식별자로 사용함
- 생성된 UUI를 포함한 Principal 객체를 반환하여 사용자를 식별함
- 반환된 Principal은 웹소켓 세션과 연결되어 통신에서 사용자 식별에 사용됨
--
핸들러 설정
--
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry){
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic", "/queue");
registry.setUserDestinationPrefix("/user");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry){
registry.addEndpoint("/ws/connect")
.setHandshakeHandler(new CustomhandshakeHandler())
.setAllowedOrigins("http://localhost:3000", "http://localhost:3001", "http://localhost:3002")
.withSockJS();
}
}
setHandshakeHandler(new CustomhandshakeHandler())로
기존 웹 소켓 핸드셰이크 과정을 커스텀한 핸들러 방식으로 대체하도록 정의한다.
--
예외 처리 응답
--
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalException {
private final SimpMessagingTemplate simpMessagingTemplate;
@MessageExceptionHandler(CustomException.class)
public void handleCustomException(CustomException e, SimpMessageHeaderAccessor headerAccessor){
String name = headerAccessor.getUser().getName();
simpMessagingTemplate.convertAndSendToUser(name, "/queue/errors", new ErrorResponseDto(e.getErrorCode(), e.getMessage(), e.getStatus()));
}
}
--
'Spring Boot' 카테고리의 다른 글
Spring과 Spring Framework 그리고 Spring boot (0) | 2025.01.10 |
---|---|
Spring boot에서 STOMP 사용하기 [ 간단한 채팅 용 ] (0) | 2024.12.03 |
Spring boot에 WebSocket 사용하기 [ 간단한 채팅 용 ] (0) | 2024.11.27 |
[IntelliJ] finished with non-zero exit value 1 에러 해결 방법 (0) | 2024.11.26 |
이메일 발송하기 (Google SMTP Server/ Gmail을 통해 발송하기) (0) | 2024.06.01 |