Мое приложение обрабатывает входы в систему с помощью @ViewScoped LoginBean
, который вводится с помощью @SessionScoped SessionBean
, в котором хранится информация о пользователе и текущий сеанс HttpSession. Это приложение позволяет пользователю N отдельные сеансы. После достижения этого предела пользователь может создать еще один, убив самого старого. Это делается в том же LoginBean
, запрашивая неуправляемый UserSessionManager
для самого старого SessionBean
, а затем аннулируя его HttpSession
.
Таким образом, входя в систему с сеансом "A", мы делаем недействительным сеанс «В». Это все идет по плану. Но затем, во время оставшихся фаз JSF, мы также теряем SessionBean
для сеанса «A». При переходе к коду CDI создается впечатление, что контекст сеанса для сеанса «А» разрушается, поэтому, когда повторное отображение заканчивается, у нас есть все новые сеансовые компоненты.
Мы используем MyFaces 2.3.6, OpenWebBeans 2.0.16 , OpenJDK 11
Это ошибка в OWB или ожидаемое поведение?
Мне также интересно, есть ли у меня фундаментальное заблуждение. Если я сохраню SessionBean
в моем UserSessionManager
и получу его во время другого сеанса , должен ли он сохранить свое первоначальное состояние или он будет переоценен в новом контексте SessionScoped
? Мне было трудно отлаживать, потому что мои объекты на самом деле являются прокси, а пользовательский интерфейс и отладчик время от времени показывают разные значения.
Обновление 27.04.20: @SessionScoped SessionBean
уничтожается орг. apache .webbeans.web.context.WebContextsService # destroyRequestContext (), где он уничтожает «PropagatedSessionContext». Этот PropagatedSessionContext устанавливается с помощью WebContextsService # destroySessionContext (), который обозначает локальный сеанс, который должен быть уничтожен, несмотря на то, что ему дается другой указанный c сеанс. Вот где мне интересно, если это ошибка в 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;
}
}