Intoduction
Spring Security 사용 중에 "사용자의 로그인 시간과 로그아웃 시간을 기록해야 한다" 라는 임무가 떨어졌다 -_-
문제는 이 로그아웃 이라는게 약간 골치 아프다.. 사용자가 직접 로그아웃 버튼을 클릭해서 로그아웃을 한다면 나이스 하지만...
대부분은 용무가 끝나면 그냥 브라우저를 끄거다 바로 다른 사이트로 넘어가게 된다. 이 경우에는 어떻게 하지?
개발자의 눈으로 보면 로그아웃 == 세션 만료로 볼 수 있다.
다른 사이트로 가거나 브라우저를 꺼버리게 되면 WAS의 기준으로 일정 시간이 지나면 세션이 만료되게 된다.
이 세션 만료를 캐취해서 처리를 하는 방법을 알아보자.
Using HttpSessionListener
서블릿의 세션 리스너를 이용한 방법이다.
아래와 같이 HttpSessionListener 인터페이스를 구현한 클래스를 만들고 web.xml 에 등록하면 된다.
스프링 시큐리티를 사용하지 않는다면 아래의 방법으로 처리하면 된다.
java
package session.destory.servlet;
import java.util.Date;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.web.context.support.WebApplicationContextUtils;
import session.destory.entity.LoginHistory;
import session.destory.security.LoginToken;
import session.destory.service.LoginHistoryService;
public class SessionManagerListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
// nothing
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// session
HttpSession session = se.getSession();
// spring web application context
ApplicationContext context = WebApplicationContextUtils
.getWebApplicationContext(se.getSession().getServletContext());
// security context
SecurityContext sc = (SecurityContext) session
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
if (sc != null) {
// authentication
Authentication auth = sc.getAuthentication();
// login history token
LoginToken loginToken = (LoginToken) auth.getPrincipal();
LoginHistory lh = loginToken.getHistory();
lh.setLogoutDate(new Date());
// update
LoginHistoryService loginHistoryService = context
.getBean(LoginHistoryService.class);
loginHistoryService.modify(lh);
}
}
}
web.xml
<!-- servlet listener -->
<listener>
<listener-class>session.destory.servlet.SessionManagerListener</listener-class>
</listener>
리스너에서 수동적으로 스프링 컨택스트와 시큐리티 컨텍스를 꺼내는게 맘에 안드는군... -_-/
Using HttpSessionEventPublisher
이번에는 스프링 시큐리티에서 지원하는 방법으로 해보겠다~!
ApplicationListener<SessionDestroyedEvent> 인터페이스를 구현한 클래스를 만들고 web.xml 에는 HttpSessionEventPublisher 클래스를 등록한다.
java
public class SessionDestoryListener implements ApplicationListener<SessionDestroyedEvent> {
private LoginHistoryService loginHistoryService;
@Autowired
public void setLoginHistoryService(LoginHistoryService loginHistoryService) {
this.loginHistoryService = loginHistoryService;
}
@Override
public void onApplicationEvent(SessionDestroyedEvent event) {
List<SecurityContext> contexts = event.getSecurityContexts();
if (contexts.isEmpty() == false) {
for (SecurityContext ctx : contexts) {
Authentication atuh = ctx.getAuthentication().getPrincipal();
// ...
}
}
}
}
spring.xml
<beans ...>
<bean id="sessionDestoryListener" class="session.destory.security.SessionDestoryListener" />
</beans>
web.xml
<!-- spring security event -->
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
뭔가 스프링스러워진 것 같다 -_-v
- 로그인 처리
- 로그아웃 처리
아래는 샘플 소스다. Tomcat 7, WebLogic 12c 에서 테스트 해봄.
war - 실행해 볼 수 있는 war 파일. 7-zip 으로 분할 압축함.
src.zip - Maven 구조로 만들어진 소스 압축함.
... 소스 만들고 나니까 오타가 있네.... Destory → Destroy
'Framework > Spring Security' 카테고리의 다른 글
AJAX Login with Spring Security (7) | 2013.12.12 |
---|---|
MySql Password Encoder (0) | 2013.09.21 |