我的应用程序使用 a 处理登录@ViewScoped LoginBean
,其中注入了@SessionScoped SessionBean
存储用户信息和当前 HttpSession 的 a。这个应用程序允许一个用户N个单独的会话。达到该限制后,用户只能通过杀死最旧的来创建另一个。这是LoginBean
通过询问UserSessionManager
最旧的非托管SessionBean
,然后使其无效来完成的HttpSession
。
因此,使用会话“A”登录,我们使会话“B”无效。这一切都按计划进行。但是,在剩余的 JSF 阶段的某个时候,我们也会丢失SessionBean
会话“A”。追溯 CDI 代码,似乎会话“A”的会话上下文正在被破坏,因此当重新显示完成时,我们拥有所有新的会话 bean。
我们正在使用 MyFaces 2.3.6、OpenWebBeans 2.0.16、OpenJDK 11
这是 OWB 中的错误,还是预期的行为?
我也想知道我是否有一个基本的误解。如果我SessionBean
在 my 中保存 a 并在不同UserSessionManager
的会话期间检索它,它应该保留其原始状态还是在新的上下文中重新评估?我一直发现调试很困难,因为我的对象实际上似乎是代理,并且 UI 和调试器有时会显示不同的值。SessionScoped
20 年 4 月 27日更新:@SessionScoped SessionBean
org.apache.webbeans.web.context.WebContextsService#destroyRequestContext() 正在销毁“PropagatedSessionContext”。这个 PropagatedSessionContext 由 WebContextsService#destroySessionContext() 设置,它指定要销毁的本地会话,尽管被赋予了不同的特定会话。这就是我想知道它是否是OWB中的错误的地方。
这是代码的简化示例:
(在此测试代码中,我将 SessionManager 设为 @ApplicationScoped bean。在原始代码中它不是,但行为是相同的。)
@Named("loginbean")
@ViewScoped
public class LoginBean implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
@Inject private ExternalContext externalContext;
@Inject private SessionBean session;
@Inject private SessionManager sessionMgr;
public String killOldestDoLogin() {
List<SessionInfo> sessions = sessionMgr.getSessions();
SessionInfo oldest = sessions.get(0);
sessionMgr.killSession(oldest.getSessionId());
return doLogin();
}
public String doLogin() {
username = username.trim();
if (username != null && username.length() > 0) {
// After a successful login, avoid session fixation attacks by
// rotating the session ID. This isn't strictly necessary as Faces has
// its own session ID that a third party wouldn't have access to
if (externalContext != null) {
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
if (request != null && request.isRequestedSessionIdValid()) {
newSessionId = request.changeSessionId();
}
}
HttpSession http = (HttpSession)externalContext.getSession(false);
session.setUsername(username);
session.setHttpSession(http);
sessionMgr.addSession(http, session);
}
return "startPage.jsf");
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
.
@Named("sessionbean")
@SessionScoped
public class SessionBean implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private HttpSession httpSession;
public void reset() {
username = null;
httpSession = null;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public HttpSession getHttpSession() {
return httpSession;
}
public void setHttpSession(HttpSession session) {
this.httpSession = session;
}
public String getSessionId() {
return httpSession == null ? "null" : this.httpSession.getId();
}
}
.
@Named("sessionmanager")
@ApplicationScoped
public class SessionManager {
private HashMap<String,HttpSession> sessionMap = new HashMap<>();
private HashMap<String,SessionBean> beanMap = new HashMap<>();
public void addSession(HttpSession http, SessionBean bean) {
beanMap.put(http.getId(), bean);
sessionMap.put(http.getId(), http);
}
public boolean killSession(String sessionId) {
HttpSession session = sessionMap.get(sessionId);
sessionMap.remove(sessionId);
beanMap.remove(sessionId);
if (session != null) {
session.invalidate();
}
return session != null;
}
public List<SessionInfo> getSessions() {
List<SessionInfo> result = new ArrayList<>();
for (String sessionId : sessionMap.keySet()) {
SessionBean bean = beanMap.get(sessionId);
HttpSession http = sessionMap.get(sessionId);
SessionInfo info = new SessionInfo();
info.setUsername(bean.getUsername());
info.setSessionId(sessionId);
info.setHttpSession(http));
result.add(info);
}
return result;
}
}
.
public class SessionInfo {
private String username;
private String sessionId;
private HttpSession httpSession;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public HttpSession getHttpSession() {
return httpSession;
}
public void setHttpSession(HttpSession httpSession) {
this.httpSession = httpSession;
}
}