Недействительная старая httpsession отбрасывает текущий контекст httpsession - PullRequest
0 голосов
/ 24 апреля 2020

Мое приложение обрабатывает входы в систему с помощью @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;
    }
}
...