Interceptor 적용을 위해 configureClientInboundChannel 메서드를 재정의
@Configuration
@EnableWebSocketMessageBroker
class WebsocketConfig(
private val env: Environment
) : WebSocketMessageBrokerConfigurer {
//...
/** interceptor 적용 **/
override fun configureClientInboundChannel(registration: ChannelRegistration) {
registration.interceptors(object : ChannelInterceptor {
override fun preSend(message: Message<*>, channel: MessageChannel): Message<*>? {
val accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor::class.java)
if (StompCommand.CONNECT == accessor?.command) {
// jwt 토큰 검증
val jwt = accessor.getNativeHeader(HttpHeaders.AUTHORIZATION)?.firstOrNull()
?.replace("Bearer", "")
?.replace(" ", "")
?: throw AccessTokenNotValidException("invalid token")
if (!isJwtValid(jwt)) throw AccessTokenNotValidException("invalid token")
else super.preSend(message, channel)
}
return super.preSend(message, channel)
}
})
}
//...
}
ChannelInterceptor 인터페이스의 preSend 메서드 정의를 통해 메세지가 수신되기 전 메세지의 데이터 검증 및 변환을 할 수 있다.
- MessageHeaderAccessor의 요청 명령어가 연결(CONNECT) 인치 확인
- MessageHeaderAccessor의 getNativeHeader() 를 통해 클라이언트에서 연결 요청 시 보낸 header의 값을 확인할 수 있다.
- Authorization 헤더의 값이 있는지 확인 후 jwt 검증을 통해 결과에 맞는 결과를 응답
- 요청이 정상적인 검증이 되었다면 클라이언트에게 101 응답을 반환하게 된다.
* messageChannel은 기본적으로 스레드풀 사이즈가 1로 지정되어있어 production환경에서는 스레드풀 조정을 권장하고있다.
val executor = ThreadPoolTaskExecutor()
executor.corePoolSize = TASK_CORE_POOL_SIZE
executor.maxPoolSize = TASK_MAX_POOL_SIZE
executor.setQueueCapacity(TASK_QUEUE_CAPACITY)
executor.setThreadNamePrefix("websocket-thread-")
executor.setBeanName(EXECUTOR_BEAN_NAME)
executor.initialize()
registration.taskExecutor(executor)
'Spring' 카테고리의 다른 글
[JMeter] 10분만에 EC2에 Spring Boot 프로젝트 배포 및 RDS(Postgres) 연결 정리 (0) | 2022.03.23 |
---|---|
[Spring Cloud] Resilience4j 를 이용한 circuitbreaker 기능 구현 (0) | 2022.03.17 |
[Spring Boot] 소켓 통신을 위한 Websocket 서버 구성 (0) | 2022.02.16 |
[Spring Boot] log4j2 보안 문제 해결 방안 - CVE-2021-44228 (0) | 2021.12.13 |
[SpringBoot] DB 연결 없이 Spring Boot 실행 시 에러 해결 (2) | 2021.12.02 |