2012-08-07 5 views
31

저는 스프링/스프링 - 보안 3.1을 사용 중이며 사용자가 로그 아웃 할 때마다 (또는 세션 시간 초과시) 어떤 조치를 취하고 싶습니다. 나는 로그 아웃을 위해 조치를 취할 수 있었지만, 세션 타임 아웃에 대해서는 작동시키지 못했습니다.로그 아웃/세션 제한 시간이 봄 보안으로 잡기

web.xml에는 ContextLoaderListener 만 지정되어 있습니다 (문제 일 수 있습니까?) 물론 DelegatingFilterProxy.

나는 이와 같이 자동 설정을 사용합니다.

<security:http auto-config="false" use-expressions="false"> 
    <security:intercept-url pattern="/dialog/*" 
     access="ROLE_USERS" /> 
    <security:intercept-url pattern="/boa/*" 
     access="ROLE-USERS" /> 
    <security:intercept-url pattern="/*.html" 
     access="ROLE-USERS" /> 

    <security:form-login login-page="/auth/login.html" 
     default-target-url="/index.html" /> 
    <security:logout logout-url="/logout" 
     invalidate-session="true" 
     delete-cookies="JSESSIONID" success-handler-ref="logoutHandler" /> 
</security:http> 

<bean id="logoutHandler" class="com.bla.bla.bla.LogoutHandler"> 
    <property name="logoutUrl" value="/auth/logout.html"/> 
</bean> 

로그 아웃 처리기는 사용자가 로그 아웃을 클릭하면 데이터베이스를 호출 할 때 호출됩니다.

하지만 세션 시간 초과를 어떻게 처리합니까?

사용자가 로그인 할 때 세션에 사용자 이름을 주입 한 다음 일반 httpsessionlistener를 사용하고 세션 시간 초과시 동일한 작업을 수행하는 한 가지 방법이 있습니다.

스프링 보안과 비슷한 방식으로 세션이 시간 초과된다는 것을 봄에 알게되면 거기에 접속하여 인증에 액세스하고 여기에서 UserDetails를 가져와 정리를 수행 할 수 있습니다.

답변

51

나는 더 간단한 해결책을 가지고있다. 이것은 로그 아웃과 세션 타임 아웃 모두에서 작동합니다.

@Component 
public class LogoutListener implements ApplicationListener<SessionDestroyedEvent> { 

    @Override 
    public void onApplicationEvent(SessionDestroyedEvent event) 
    { 
     List<SecurityContext> lstSecurityContext = event.getSecurityContexts(); 
     UserDetails ud; 
     for (SecurityContext securityContext : lstSecurityContext) 
     { 
      ud = (UserDetails) securityContext.getAuthentication().getPrincipal(); 
      // ... 
     } 
    } 

} 

web.xml :

<listener> 
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> 
</listener> 
+1

내 pov에서 더 나은 솔루션입니다. 내가했던 것처럼 이것을 사용하는 것이 좋습니다. Thx John. Btw : "정상적인"로그 아웃도 처리합니다! –

+0

'Spring Security'를 사용하면서 여기서 언급 한 세션은 HTTPSession과 동일하거나 Spring Security의 세션입니까? 대안으로, 새로운 '봄 세션'구성 요소가 솔루션을 제공하는 것 같습니다. http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedevent – yathirigan

+5

@yathirigan 확실하지 않습니다. "봄 보안 세션"의 의미. 스프링 시큐리티는 HTTP 세션을 사용하므로 기본적으로 똑같습니다. – John29

3

잘못된 요청한 세션이 SessionManagementFilter에 의해 감지되면 SimpleRedirectInvalidSessionStrategy을 사용하여 URL로 리디렉션 할 수 있습니다.

샘플의 ApplicationContext는 다음과 같습니다

<http> 
    <custom-filter ref="sessionManagementFilter" before="SESSION_MANAGEMENT_FILTER" /> 
<http> 


<beans:bean id="sessionManagementFilter" class="org.springframework.security.web.session.SessionManagementFilter"> 
    <beans:constructor-arg name="securityContextRepository" ref="httpSessionSecurityContextRepository" /> 
    <beans:property name="invalidSessionStrategy" ref="simpleRedirectInvalidSessionStrategy " /> 
</beans:bean> 

<beans:bean id="simpleRedirectInvalidSessionStrategy" class="org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy"> 
    <beans:constructor-arg name="invalidSessionUrl" value="/general/logins/sessionExpired.jsf" /> 
    <beans:property name="createNewSession" value="false" /> 
</beans:bean> 
<beans:bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/> 

당신은 또한뿐만 아니라 Ajax 요청을 처리하는 방법에 JSF 2, Spring Security 3.x and Richfaces 4 redirect to login page on session time out for ajax requests 참조, JSF를 사용하는 경우.

UPDATE은 : 이러한 경우에, 당신은 HttpSessionEventPublisher 확장 할 수 있으며,이 같은 sessionDestroyed 이벤트를 수신 :

package com.examples; 
import javax.servlet.http.HttpSessionEvent; 

import org.springframework.security.web.session.HttpSessionEventPublisher; 


public class MyHttpSessionEventPublisher extends HttpSessionEventPublisher { 

    @Override 
    public void sessionCreated(HttpSessionEvent event) { 
     super.sessionCreated(event); 
    } 

    @Override 
    public void sessionDestroyed(HttpSessionEvent event) { 
     //do something 
     super.sessionDestroyed(event); 
    } 

} 

를 다음과 같이 당신의 web.xml이 리스너를 등록 :

<listener> 
    <listener-class>com.examples.MyHttpSessionEventPublisher</listener-class> 
</listener> 
+0

제안 해 주셔서 감사합니다.하지만 문제가 해결 될 것이라고 생각하지 않습니다. 세션 시간 제한을 잡아야하는데 사용자가 요청할 때까지 기다릴 수 없습니다 (예 : 브라우저가 닫히는 등 가끔씩 수행하지 않음). 사용자가 다른 사람을 위해 잠글 수있는 잠금 장치를 해제해야합니다. 아니요, JSF를 사용하지 않고 스프링 및 속도 만 사용하십시오. – Perre

+0

답변이 업데이트되었습니다! – Ravi

+0

Authentication 개체를 가져 오는 방법이 있습니까? 그것을 시도했지만 SecurityContextHolder.getContext(). getAuthentication() 통해 가져 오는 null을 반환합니다. 타임 아웃 전에 세션에 바인딩 된 인증을 가져와야합니다. 내 말은, 이것은 HttpSession 만료 이벤트처럼 보입니다. 이 이벤트에서 인증 된 UserDetails 개체를 어떻게 가져올 수 있습니까? – Perre

6

좋아, 나는 해결책을 얻었고, 내가 원하는만큼 좋지는 않지만 결과는 나에게 달려있다.

ApplicationContext를 보유 할 수있는 bean을 만듭니다.

public class AppCtxProvider implements ApplicationContextAware { 
private static WeakReference<ApplicationContext> APP_CTX; 

@Override 
public void setApplicationContext(ApplicationContext applicationContext) 
     throws BeansException { 
    APP_CTX = new WeakReference<ApplicationContext>(applicationContext); 
} 

public static ApplicationContext getAppCtx() { 
    return APP_CTX.get(); 
} 
} 

나는 내가

지금 내가 세션의 정리 및의 사용자를 할 필요가 봄 콩이 sessionRegistry.getSessionInfo (sessionId가)를 통해 된 UserDetails를 얻을 파괴에 HttpSessionEventPublisher 구현 세션이 시간 초과되었습니다.

public class SessionTimeoutHandler extends HttpSessionEventPublisher { 
@Override 
public void sessionCreated(HttpSessionEvent event) { 
    super.sessionCreated(event); 
} 

@Override 
public void sessionDestroyed(HttpSessionEvent event) { 
    SessionRegistry sessionRegistry = getSessionRegistry(); 
    SessionInformation sessionInfo = (sessionRegistry != null ? sessionRegistry 
      .getSessionInformation(event.getSession().getId()) : null); 
    UserDetails ud = null; 
    if (sessionInfo != null) { 
     ud = (UserDetails) sessionInfo.getPrincipal(); 
    } 
    if (ud != null) { 
       // Do my stuff 
    } 
    super.sessionDestroyed(event); 
} 

private SessionRegistry getSessionRegistry() { 
    ApplicationContext appCtx = AppCtxProvider.getAppCtx(); 
    return appCtx.getBean("sessionRegistry", SessionRegistry.class); 
} 
관련 문제