본문 바로가기
스프링 공부/공부내용

스프링부트 웹소켓 통신 전 핸드쉐이크 인터셉터 (handshake Interceptor)로 세션정보

반응형

인터셉터(interceptor)란 ?

스프링에서 controller 에 접근하기 이전에 가로체서 처리를 할 수 있도록 만드는 기능입니다. 

톰켓에서 dispatcher servlet에 접근할 때는 이전에 가로체서 처리할 수 있는데 이 기능은 필터(filter) 입니다. 

 

웹소켓에서 연결하기 이전에 http 통신을 통해 핸드쉐이크 과정이 일어나는데 이때 핸드쉐이크 인터셉터를 통해 세션정보를 가져올 수 있습니다.

 

HandShake Interceptor 란? 

웹 소켓에서 http handshake 연결과정에서 사용할 수 있는 인터셉터입니다. 아래는 공식문서에서 handshake 인터셉터의 설명입니다.

Interceptor for WebSocket handshake requests. Can be used to inspect the handshake request and response as well as to pass attributes to the target 
WebSocketHandler.

 

HandShake Interceptor 언제 쓰고 왜 쓸까?

핸드쉐이크 인터셉터를 통해 세션정보를 가져올 수 있습니다. 따라서 로그인된 사용자만 웹소켓을 이용하게 하고 싶다면 쓸 수 있겠죠? 또한 http 헤더에서 필요한 정보를 꺼내서 웹소켓 세션에 저장하고 싶다면 사용할 수 있습니다.

예시

 

handShake Interceptor 적용하기

 

HandShakeInterceptor

@Component
public class SocketInterceptor implements HandshakeInterceptor{

	@Override
	public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Map<String, Object> attributes) throws Exception {


		HttpServletRequest req = ((ServletServerHttpRequest)request).getServletRequest();
		HttpSession session  =  req.getSession(false);

		System.out.println("Session >> " +  session);

		if(session != null) {
			MemberDto dto = (MemberDto) session.getAttribute("user_info");
			String user_id = dto.getUser_id();
			attributes.put("user_id", user_id);
			return true;
		}
		throw new AuthException("로그인 해주세요");
		
	}

	@Override
	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Exception exception) {
		// TODO Auto-generated method stub
		
	}

}

handShakeInterceptor에서  SererHttpRequest를 통해 JSSESION 정보를 찾는 과정예제입니다. attributes에 데이터를 저장하게 되면 websocketSession 에서 꺼내 사용할 수 있게 됩니다.

WebSocketConfiguration

package com.ssafy.web.socket.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import com.ssafy.web.socket.SocketInterceptor;
import com.ssafy.web.socket.WebSocketHandler;

@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
	
	@Autowired
	SocketInterceptor SocketInterceptor;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry
			.addHandler(webSocketHandler(), "/chat")
			.setAllowedOriginPatterns("*").addInterceptors(SocketInterceptor);
		
		registry
		.addHandler(webSocketHandler(), "/chat")
		.setAllowedOriginPatterns("*")
		.withSockJS().setInterceptors(SocketInterceptor);

	}

	@Bean
	public WebSocketHandler webSocketHandler() {
		return new WebSocketHandler();
	}

	
}

이제  endpoint에 addInterceptors 를 통해 인터셉터를 추가해주면 핸드쉐이크 인터셉터가 작동하게 됩니다.

 

이제 웹소켓 헨들러에서 필요한 정보를 꺼내고 싶을 떄는 아래와 같이 사용해 사용자 정보를 꺼낼 수 있습니다.

	public String getIdFromSession(WebSocketSession session) {
		String id = null;
		String key = null;

		for (Entry<String, Object> map : session.getAttributes().entrySet()) {
			key = (String) map.getKey();

			if (key.equals("user_id")) {
				return (String) map.getValue();
			}
		}
		return null;
	}

 

이제 로그인 하지 않은 사용자가 웹소켓 주소에 바로 접근하면 어떻게 될까요? 아래처럼 Exception이 발생하게 됩니다.