트러블슈팅

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을 검증하도록 했다.