CDI/JSF 如何处理会话超时

CDI/JSF How to handle session timeout

我有一个 Jakarta EE8 ( CDI 2 / Weld / JSF 2.3 / Wildfly ) 应用程序,我需要在用户注销时执行一些清理代码,手动注销没问题,但我现在需要在注销时触发一个事件由于会话超时自动发生,为了处理这个我已经尝试了以下两种方法...

@Named
@SessionScoped
public class HttpSessionObservers implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    @Inject private Logger log;
    @Inject SecurityContext securityContext;

    @PreDestroy
    public void processSessionScopedDestroying() {
        
        log.debug("Http Session predestroy");   
        Principal principal = securityContext.getCallerPrincipal(); //<----is null
        //...do some cleanup/logging operations on user account
    }

}

上面的@PreDestroy回调在会话超时时触发,但登录用户(主体)始终为空,所以看起来他们已经注销,所以我无法获得用户。

@Named
public class HttpSessionObservers implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    @Inject private Logger log;
    @Inject private Event<UserLogoutEvent> userLogoutEvent;
    
    public void processSessionScopedInit(@Observes @Initialized(SessionScoped.class) HttpSession payload) {
        log.debug("Http Session initialised");
    }

    public void processSessionScopedDestroying(@Observes @BeforeDestroyed(SessionScoped.class) HttpSession payload) {
        //Never fires
        log.debug("Http Session predestroy");   
        Principal principal = securityContext.getCallerPrincipal();
        //...do some cleanup/logging operations on user account
    }

    public void processSessionScopedDestroyed(@Observes @Destroyed(SessionScoped.class) HttpSession payload) {
        log.debug("Http Session destroyed");    
    }
}

在这里,@BeforeDestroyed 事件从未被触发,似乎无法找到此工作的任何示例,它在其他范围内工作正常。

实现您自己的 HttpSessionListener 并用 @WebListener 注释容器应该识别这一点,并将在您的实现中调用 sessionDestroyed() 方法。您的 class 符合 CDI 注入条件,因此在 sessionDestroyed() 中,您可以触发一个事件并使用 CDI 观察器监听它。

参考:https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpSessionListener.html

编辑:

然后试试这个:将您的 HttpSessionListener 实现范围限定为 @ApplicationScoped。有 sessionId/username 的同步地图。在 sessionCreated() 中插入地图,在 sessionDestroyed() 中在 finally 块中删除它。

该容器还将有几个隐式 HttpSessionListener,因此您的容器有可能在会话失效后很长时间内被调用。如果是这样,您可以使用另一种技术首先插入 HttpSessionListener impl。先试试上面的技术,然后我们再深入研究这个。