简体   繁体   English

Spring Boot,Spring Security,会话范围Bean,会话超时问题,@ PreDestroy

[英]Spring Boot, Spring Security, session-timeout issue with session scoped Bean, @PreDestroy

Fisrt, I need to say that I'm using session scoped bean. Fisrt,我需要说我正在使用会话范围的bean。 So before session is closed the preDestroy() method is invoked 因此,在会话关闭之前,将调用preDestroy()方法

@Component
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "session")
public class MySessionBean {

    @PreDestroy
    public void preDestroy() {

        //Do Smth with using Security principal

    }
}

When I logout by using Spring Security utils everything goes fine, the preDestroy() method is called. 当我使用Spring Security utils 注销时一切正常, preDestroy()方法。

The main problems come when I use 我使用时会出现主要问题

server.session-timeout = 60 or = 1 in application.properties application.properties server.session-timeout = 60= 1

  1. preDestroy() is called approximately in 2.5 minutes after session has opened. 会话打开后大约在2.5分钟内调用preDestroy()
  2. And much more interesting is that SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 更有趣的是SecurityContextHolder.getContext().getAuthentication().getPrincipal(); is null . null
    BUT I've successfully loged out. 但我已经成功了。

Also I've tried a 我也试过了

@Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
    return (ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) -> 
        configurableEmbeddedServletContainer.setSessionTimeout(1, TimeUnit.MINUTES);
    }

I have the same result. 我有相同的结果。
Also the problem exists while using Provided Tomcat 使用Provided Tomcat时也存在问题

UPDATE: 更新:

The weird thing is that if I manually after 1 minute check the session existence the method preDestroy() is called immediately. 奇怪的是,如果我在1分钟后手动检查会话是否存在,则立即调用方法preDestroy() But Security Principal is already null Security Principal已经是null


Thanks in Advance! 提前致谢!

When a session does timeout the SecurityContextHolder.getContext().getAuthentication().getPrincipal() will always return null . 当会话超时时, SecurityContextHolder.getContext().getAuthentication().getPrincipal()始终返回null The SecurityContext is only filled when a request comes in, one of the filters does that. SecurityContext仅在请求进入时填充,其中一个过滤器执行此操作。 When a session times out the filters will of course not be invoked and as such the SecurityContext not filled. 当会话超时时,过滤器当然不会被调用,因此SecurityContext没有被填充。

Instead create a bean that implements ApplicationListener<HttpSessionDestroyedEvent> . 而是创建一个实现ApplicationListener<HttpSessionDestroyedEvent>的bean。 The HttpSessionDestroyedEvent has a method getSecurityContexts that returns the SecurityContext s as originally in the HttpSession . HttpSessionDestroyedEvent有一个方法getSecurityContexts ,它返回最初在HttpSessionSecurityContext

public class YourListener implements ApplicationListener<HttpSessionDestroyedEvent> {

    public void onApplicationEvent(HttpSessionDestroyedEvent evt) {
        for (SecurityContext ctx : evt.getSecurityContexts() ) {
             Authentication auth = ctx.getAuthentication();
             Object principal = auth.getPrincipal();
             // Do your thing with the principal.
        }
    }
}

As M. Deinum said: 正如M. Deinum所说:

There is a thread which check about every x seconds if sessions are invalid. 如果会话无效,则会有一个每隔x秒检查一次的线程。 So when your set your timeout to 1 minute it is 1 minute + a bit more before your sessions is actually cleared. 因此,当您将超时设置为1分钟时,它会在您的会话实际清除之前为1分钟+多一点。 When you check the session yourself, the invalid session is already cleaned as then it it is forcefully checked. 当您自己检查会话时,无效会话已经被清除,因为它被强制检查。

So delay of preDestroy() invocation has been explained. 因此解释了preDestroy()调用的延迟。

The next problem was how to get Security Principal after SESSION-TIMEOUT 下一个问题是如何在SESSION-TIMEOUT之后获得Security Principal

NOTE that by implementing 注意通过实施

  • ApplicationListener<HttpSessionDestroyedEvent>
  • HttpSessionListener
  • Session scope bean

    the

SecurityContextHolder.getContext().getAuthentication() == null when appropriate destroy method is called 调用适当的destroy方法时, SecurityContextHolder.getContext().getAuthentication() == null

To get principal visit relatedStackPost 要获得principal访问relatedStackPost

After you'll do that implement HttpSessionListener 在你做完之后实现HttpSessionListener

@Component
public class MySessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        ...
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        HttpSession httpSession = httpSessionEvent.getSession();
        SecurityContext securityContext = (SecurityContextImpl) httpSession.getAttribute("SPRING_SECURITY_CONTEXT");

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM