0

我的应用程序使用 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;
    }
}
4

0 回答 0