트러블슈팅
WebSocket 연결 시, JWT Token Error
계양 꿀주먹
2024. 8. 15. 20:29
문제
다른 요청에 대해서는 header의 token을 정상적으로 가져오지만 Web Socket의 요청에서 계속 Spring Security Context 에서 사용자의 정보를 가져올 때, 에러가 발생했다.
원인
- 정상적인 요청
Jul 23 09:24:38 ip-172-31-44-203 web[1099434]: token : Bearer aaaaaaaaabbbbbbbbbbbcccccccc
- websocket 의 요청
Jul 23 09:22:29 ip-172-31-44-203 web[1099434]: token : null
- http와 WebSocket의 Security chain, config는 완전히 독립적이다.
- 기존 AuthenticationProvider는 Websocket Authentication에 관여하지 않는다.
- Websocket에 CONNECT 되면 해당 user는 websocket session에 저장되며 이후 메세지에는 인증 과정을 거치지 않는다.
해결
- WebSocketConfig
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(stompHandler);
}
- StompHandler
@Component
@RequiredArgsConstructor
public class StompHandler implements ChannelInterceptor {
private final JwtUtil jwtUtil;
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
String accessToken = "";
// 연결 요청에 대해 실행
if(accessor.getCommand() == StompCommand.CONNECT) {
accessToken = accessor.getFirstNativeHeader("Authorization");
}
if (StringUtils.hasText(accessToken) && accessToken.startsWith("Bearer ")) {
accessToken = accessToken.substring(7);
}
try {
jwtUtil.validateAccessToken(accessToken);
} catch (ExpiredJwtException e) {
throw new CatchStudyException(ErrorCode.EXPIRED_ACCESS_TOKEN);
}
Authentication authentication = jwtUtil.getAuthentication(accessToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
accessor.setUser(authentication);
return message;
}
}
WebSocketConfig에 ChannelInterceptor를 구현한 클래스를 만들어 stomp 메시지 헤더에 접근해 socket이 연결되었을 때,
token을 검증하도록 했다.