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。先试试上面的技术,然后我们再深入研究这个。
我有一个 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。先试试上面的技术,然后我们再深入研究这个。