스프링시큐리티 중복로그인(동시접속) 제한처리 - 다중서버환경
스프링시큐리티에서 중복로그인 제한은 사실 간단하게 처리할 수 있다.
security-context.xml
<http>
<session-management>
<concurrency-control max-sessions="1"></concurrency-control>
</session-management>
</http>
위 코드처럼 간단히 max-sessions="1" 속성으로 동접을 제한할 수 있다.
하지만, WAS서버가 단일구성이 아니라면
WEB서버 설정에 따라 다른 서버로 세션이 붙게 되면 동접이 가능해지게 된다.
다른전략으로 접근을 해야했다.
로그인은 AuthenticationSuccessHandler 핸들러를 등록하여
사용자가 로그인을 성공할 시 DB에 사용자로그인 상태를 INSERT하였고
로그아웃은 ApplicationListener의 구현체를 등록하여
사용자의 세션종료 브로드캐스팅을 캐치하여 사용자로그인정보를 DELETE하였다.
security-context.xml
<http>
...
<form-login login-page="/common/auth/denied" authentication-success-handler-ref="customAuthenticationSuccessHandler" />
...
</http>
CustomAuthenticationSuccessHandler.java
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
@Component
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response
, Authentication authentication) throws IOException, ServletException {
// 로그인성공한 유저정보
User user = (User) authentication.getPrincipal();
// 세션아이디
String sessionId = request.getSession().getId();
// 로그인정보 DB insert처리
super.onAuthenticationSuccess(request, response, authentication);
}
}
SessionDestoryListener.java
import java.util.List;
import org.springframework.context.ApplicationListener;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.session.SessionDestroyedEvent;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
@Component
public class SessionDestoryListener implements ApplicationListener<sessiondestroyedevent> {
@Override
public void onApplicationEvent(SessionDestroyedEvent event) {
List<securitycontext> contexts = event.getSecurityContexts();
if (!contexts.isEmpty()) {
for (SecurityContext ctx : contexts) {
// 로그아웃 된 유저정보
User cu = (User) ctx.getAuthentication().getPrincipal();
// 로그아웃 DB delete처리
}
}
}
}
그 다음은 자유롭게
로그인 페이지에서 DB에 해당 사용자의 세션이 존재하고 있는지 체크한 후
"접속중인 사용자가 있습니다. 연결을 끊고 로그인 하시겠습니까? 라는
간단한 화면처리나 alert메시지 처리를 해주면 된다.
단! 서버 재기동 시 SessionDestoryListener이벤트를 받지 못하기 때문에
사용자가 재로그인 시도 시 DB에 로그인정보가 있기 때문에 주의하여야 한다.
물론 세션클러스터링이 잘되고 있는 환경이라면 크게 문제는 없을 것 같다.
(정책적으로 기존로그인 사용자는 튕겨내는 방식을 추천)
다중서버환경에서는 근본적으로 Redis같은 캐시형 DB로 세션관리하는게
제일 바람직하지 않을까 생각해본다.
출처: http://nuridan.tistory.com/1 [숙취의 개발노트]
'Spring Framework > Spring Core' 카테고리의 다른 글
[Spring] web.xml 기본 설정 (0) | 2020.06.10 |
---|---|
[spring] 스프링 MVC 인터페이스 구현 클래스 (0) | 2020.06.10 |
[Spring] 스프링 MVC 패턴 개요 (0) | 2020.06.10 |
[Spring] AOP 용어 설명 (0) | 2020.06.10 |
[Spring] 의존관계 주입 (0) | 2020.06.10 |
response.sendRedirect() 사용시 주의사항 (0) | 2019.01.08 |
Spring에서 인터셉터 적용하기 (0) | 2019.01.03 |
Spring Transaction(트랜잭션) (0) | 2018.07.20 |