Fisrt,我需要说的是我正在使用会话范围的bean。因此,在关闭会话之前,会调用preDestroy()方法

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

    @PreDestroy
    public void preDestroy() {

        //Do Smth with using Security principal

    }
}

当我通过使用 Spring Security 实用程序注销一切正常时,将调用preDestroy()方法。

当我使用时主要的问题来了
server.session-timeout = 60中的= 1application.properties
会话打开后大约在 2.5分钟中调用
  • preDestroy()
  • 更有趣的是SecurityContextHolder.getContext().getAuthentication().getPrincipal();null但我已成功注销。

  • 我也尝试过
    @Bean
    public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
        return (ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) ->
            configurableEmbeddedServletContainer.setSessionTimeout(1, TimeUnit.MINUTES);
        }
    

    我有相同的结果。
    使用Provided Tomcat时也存在问题

    更新:

    奇怪的是,如果我在一分钟后手动检查会话
    存在方法preDestroy()被立即调用。但
    Security Principal已经是null
    提前致谢!

    最佳答案

    当会话超时时,SecurityContextHolder.getContext().getAuthentication().getPrincipal()将始终 返回null。仅当请求进入时才填充SecurityContext,其中一个过滤器会执行该操作。当会话超时时,过滤器当然不会被调用,因此SecurityContext不会被填充。

    而是创建一个实现ApplicationListener<HttpSessionDestroyedEvent>的bean。 HttpSessionDestroyedEvent 具有一种 getSecurityContexts 方法,该方法返回SecurityContext中最初包含的HttpSession

    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.
            }
        }
    }
    

    10-08 16:10