2

我正在使用 Java EE 6(JSF CDI EJB)开发一个 Web 应用程序,该应用程序不允许并发登录(相同的用户和密码)。

我喜欢的是:

如果用户登录两次,则第一个会话需要失效,并且旧会话数据(包括所有具有 SessionScope 的 CDI Bean 或来自 Apache CODI 的 WindowScope 等其他范围)被传输到新会话。

这有点像想要的会话劫持方法:-)

4

3 回答 3

0

Java EE 6 中没有这种固有机制。

由于我无法想象您想将正在进行的用例(例如,打开的结帐流程)从一个会话转移到另一个会话,因此我建议您只需跟踪用户的 GUI 状态

RESTful URL 听起来是一种理想的方法。保留最后一个用户 URL/用户操作(例如www.myapp.com/orders/new/12)并在新登录时重新打开它。

如果您不想将其保留在数据库中,则应用程序范围的映射用户 ID / url 可能是 KISS 方式。

于 2012-07-17T06:43:58.873 回答
0

您可以为用户使用无状态 bean,因此每次尝试登录/重新登录时,当前会话都会失效(在登录过程开始时)

考虑这种方法:

try {           
   session = request.getSession();   //the request is passed by another page or action
   if(session.getAttribute("user") != null) {

           //your code to forward or handle the existing user (re-log in/ do nothing etc.)
}
于 2012-07-17T08:42:53.700 回答
0

我在过滤器的帮助下解决了这个问题

公共类 SessionReplicationFilter 实现过滤器 {

@Inject
SessionReplicationManager manager;

public SessionReplicationFilter() {
}


@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    //Process chain first 
    if (chain != null) {
        chain.doFilter(request, response);
    }

    //check http request
    if (request instanceof HttpServletRequest) {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        // Retrieve the session and the principal (authenticated user)
        // The principal name is actually the username
        HttpSession session = httpRequest.getSession();
        Principal principal = httpRequest.getUserPrincipal();
        if (principal != null && principal.getName() != null && session != null) {
            manager.checkExistingSession(principal.getName(), session)) 
        }
    }

}

@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void destroy() {

}

}

经理看起来如下

@ApplicationScoped 公共类 SessionReplicationManager {

private Map<String, HttpSession> map = new ConcurrentHashMap<String, HttpSession>();


public boolean checkExistingSession(String user, HttpSession session) {
    if (map.keySet().contains(user)) {
        if (!session.getId().equals(map.get(user).getId())) {
            System.out.println("User already logged in ");
            HttpSession oldSession = map.get(user);
            // copies all attributes from the old session to the new session (replicate the session)
            Enumeration<String> enumeration = oldSession.getAttributeNames();
            while (enumeration.hasMoreElements()) {
                String name = enumeration.nextElement();
                System.out.println("Chaning attribut " + name);
                session.setAttribute(name, oldSession.getAttribute(name));
            }
            // invalidates the old user session (this keeps one session per user)
            oldSession.invalidate();
            map.put(user, session);
            return true;
        }
    } else {
        System.out.println("Putting "+user+" into session cache");
        map.put(user, session);
        return false;
    }
    return false;
}

}

它与 CoDI ViewScoped 带注释的 Bean 配合得很好

如果第一个用户每次(AJAX)请求都无效导致会话过期异常,即使使用恢复会话按钮也可以轻松处理

viewscoped bean 的唯一小问题是,它们获得了新的视图 ID。通过将它们改回原点,一切正常。

我需要补充的东西:

  • 自动注销(ajax 轮询,websockets,...)
  • 存储所有 viewscoped-id 的某种注册表

此评论中缺少:

  • web.xml 配置

问候

于 2012-07-17T11:05:13.333 回答