Spring Security Session Destroy

Posted at 2013. 10. 27. 12:39 | Posted in Framework/Spring Security
반응형

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 으로 분할 압축함.


session.destory.zip.001


session.destory.zip.002



src.zip - Maven 구조로 만들어진 소스 압축함.


session.destory.src.zip


 

... 소스 만들고 나니까 오타가 있네.... Destory → Destroy


반응형

'Framework > Spring Security' 카테고리의 다른 글

AJAX Login with Spring Security  (7) 2013.12.12
MySql Password Encoder  (0) 2013.09.21
//