StompSubProtocolHandler : Error publishing SessionConnectedEvent 해결

Seunghso·2024년 1월 13일

Spring

목록 보기
1/1

발생배경

HttpSession 을 WebSocket Session과 통합하는 시도중에 발생하였다.
로그인을 하고 HttpSession이 생긴 이후에 웹소켓에 연결하려고 시도하면 문제가 생겼다.

발생원인

LocalSimpUser simpUser = this.users.get(name);
해당 에러가 발생하는 이유는 위 코드에서 name 이 Null 이었고
users 는 ConcurrentHashMap 이었기에 key가 Null이 될 수 없어서 발생했다.

public class DefaultSimpUserRegistry implements SimpUserRegistry, SmartApplicationListener

	{...}
    
	@Override
	public void onApplicationEvent(ApplicationEvent event) {
    
		{...}
        
		else if (event instanceof SessionConnectedEvent) {
			Principal user = subProtocolEvent.getUser();
			if (user == null) {
				return;
			}
			String name = user.getName();
			if (user instanceof DestinationUserNameProvider destinationUserNameProvider) {
				name = destinationUserNameProvider.getDestinationUserName();
			}
			synchronized (this.sessionLock) {
				LocalSimpUser simpUser = this.users.get(name);
				if (simpUser == null) {
					simpUser = new LocalSimpUser(name, user);
					this.users.put(name, simpUser);
				}
				LocalSimpSession session = new LocalSimpSession(sessionId, simpUser);
				simpUser.addSession(session);
				this.sessions.put(sessionId, session);
			}
            
            {...}
		}

해당 name이 Null이 안되게 바꾸어보자

  1. name = user.getName();

  2. Principal user = subProtocolEvent.getUser();

  3. Principal의 구현체 => UsernamePasswordAuthenticationToken

  4. public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer
    	
        {...}
        
        public String getName() {
            if (this.getPrincipal() instanceof UserDetails) {
                return ((UserDetails)this.getPrincipal()).getUsername();
            } else if (this.getPrincipal() instanceof AuthenticatedPrincipal) {
                return ((AuthenticatedPrincipal)this.getPrincipal()).getName();
            } else if (this.getPrincipal() instanceof Principal) {
                return ((Principal)this.getPrincipal()).getName();
            } else {
                return this.getPrincipal() == null ? "" : this.getPrincipal().toString();
            }
        }
    
  5. this.getPrincipal() = SessionUser 로 내가 만들었던 CustomClass로 UserDetails를 구현한다.
    따라서 SessionUser의 getUserName()의 값이 Null이 되지 않도록 만들어야 한다.

배운점

이 문제를 해결하면서 배운점이 있다기 보다 나의 부족함을 알게 되는 계기가 되었다.
또 하나의 디테일은 SimpMessagingTemplateconvertAndSendToUser(String user, String destination, Object payload) 의 user 에는 여기서 UserDetails의 getUserName()이 된다.

profile
Better than yesterday

0개의 댓글