JavaEE + Glassfishv3.0.1 : Losing session attribute (SessionId is not the same between request)

标签 java session jakarta-ee glassfish glassfish-3

我有一个 home.jsf ,它调用一个登录 servlet,该 servlet 会根据用户名和密码查看数据库并查询出 user 对象。然后,我将该 user 对象保存到属性名称 user 下的 session 中,如下所示 request.getSession().setAttribute("user", user);

protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    boolean remember = "true".equals(request.getParameter("remember"));
    //Hashing the password with SHA-256 algorithms
    password = hash(password);
    HttpSession s = request.getSession(false);
    if (s != null) {
        logger.log(Level.INFO, "Id: {0}", s.getId());
    }
    User user = scholarEJB.findUserByUserNamePassword(username, password);
    try {
        if (user != null) {
            request.login(username, password);
            request.getSession().setAttribute("user", user);                
            if (remember) {
                String uuid = UUID.randomUUID().toString();
                UserCookie uc = new UserCookie(uuid, user.getId());
                scholarEJB.persist(uc);
                Helper.addCookie(response, Helper.COOKIE_NAME, uuid, Helper.COOKIE_AGE);                    
            }else{
                //If the user decide they dont want us to remember them
                //anymore, delete any cookie associate with this user off
                //the table
                scholarEJB.deleteUserCookie(user.getId());
                Helper.removeCookie(response, Helper.COOKIE_NAME);
            }
            response.sendRedirect("CentralFeed.jsf");
        }else{
            response.sendRedirect("LoginError.jsf");
        }
    } catch (Exception e) {
        response.sendRedirect("LoginError.jsf");
    }

然后我有一个映射到所有安全页面的文件管理器,它将尝试从 session 中检索用户对象,否则,将我重定向到 home.jsf 以再次登录

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    HttpSession s = request.getSession(false);        
    if (s != null) {
        logger.log(Level.INFO, "Id Before: {0}", s.getId());
    }
    User user = (User) request.getSession().getAttribute("user");
    s = request.getSession(false);
    if (s != null) {
        logger.log(Level.INFO, "Id After: {0}", s.getId());
    }
    if (user == null) {
        String uuid = Helper.getCookieValue(request, Helper.COOKIE_NAME);
        if (uuid != null) {
            user = scholarEJB.findUserByUUID(uuid);
            if (user != null) {
                request.getSession().setAttribute("user", user);    //Login
                Helper.addCookie(response, Helper.COOKIE_NAME, uuid, Helper.COOKIE_AGE);
            } else {
                Helper.removeCookie(response, Helper.COOKIE_NAME);
            }
        }
    }
    if (user == null) {
        response.sendRedirect("home.jsf");
    } else {
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
        response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
        response.setDateHeader("Expires", 0); // Proxies.
        chain.doFilter(req, res);
    }

现在,正如您在这里看到的,我也操纵了一些 Cookie,但这仅在我选中记住我时才会发生。现在我位于 CentralFeed.jsf 中,但从这里发送的任何请求都会返回到 home.jsf 以便再次登录。我通过调试器,所以当我第一次登录时,第一次进入过滤器时,我通过 request.getSession().getAttribute("user"从 session 中成功检索了 user 对象”);。但之后,当我返回过滤器时,我不再使用 session 属性user。我在 web.xml 中将 session 超时设置为 30 分钟

<session-config>
    <session-timeout>
        30
    </session-timeout>
</session-config> 

编辑

现在,当我打印出请求之间的 session ID 时,它实际上是不同的 session ID,但我不知道为什么?请帮忙。

编辑2

@BalusC:我实际上确实使 session 无效。当时,您向我展示了当用户在其他地方登录时如何强制注销(http://stackoverflow.com/questions/2372311/jsf-how-to-invalidate-an-user-session-when-he-logs-两次使用相同的凭证)。所以在 User 实体里面我有这个

@Entity
public class User implements Serializable, HttpSessionBindingListener {
   @Transient
   private static Map<User, HttpSession> logins = new HashMap<User, HttpSession>();    

   @Override
   public void valueBound(HttpSessionBindingEvent event) {
     HttpSession session = logins.remove(this);
     if (session != null) {
        session.invalidate();  //This is where I invalidate the session
     }
     logins.put(this, event.getSession());
   }

   @Override
   public void valueUnbound(HttpSessionBindingEvent event) {
     logins.remove(this);
   }
}

valueBound 方法中,我确实使 session 无效,当我将其注释掉时,一切正常。我浏览了调试器,发生的情况如下。当我第一次登录时,LoginServlet 捕获它。然后 request.getSession().setAttribute("user", user); 行调用 valueBound 方法。然后 Filter 被调用,chain.doFilter(req, res); 行再次调用 valueBound 方法,这一次,session 是不为 null,因此它进入 if 和 session.invalidate。我评论了 session.invalidate ,它起作用了。但正如您可能已经猜到的那样,当用户在其他地方登录时我无法强制注销。您是否看到此 BalusC 的明显解决方案?

最佳答案

HTTP session 由 JSESSIONID cookie 维护。确保您的 Helper.COOKIE_NAME 不使用相同的 Cookie 名称,否则它将覆盖 session Cookie。

如果不是这样的话,那我就不知道了。我将使用 Firebug 来调试 HTTP 请求/响应 header 。在全新 session 的第一个 HTTP 响应中,您应该会看到 Set-Cookie header 以及带有 session ID 的 JSESSIONID cookie。在同一 session 中的所有后续请求中,您应该会看到 Cookie header 以及带有 session ID 的 JSESSIONID cookie。

Cookie header 不存在或包含 JSESSIONID cookie 时,将创建一个新 session (对于服务器端)不存在 session ID(因为它是已失效),或者当服务器使用具有不同 session ID 的新 Set-Cookie header 进行响应时。这应该可以帮助您找出罪魁祸首。是服务器生成了新的 session cookie吗?或者是客户端没有发回 session cookie?

如果是服务器,则在服务器端的某个位置 session 已过期/无效。尝试在 HttpSession#invalidate() 上放置一个断点以进一步确定它。

如果是客户端(这会很奇怪,因为它似乎很好地支持 cookies),那么尝试对重定向 URL 进行编码以包含 JSESSIONID

response.sendRedirect(response.encodeRedirectURL(url));

如有必要,请尝试使用不同的客户端以排除其中一个或另一个。

关于JavaEE + Glassfishv3.0.1 : Losing session attribute (SessionId is not the same between request),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5156942/

相关文章:

java - 签名的 Amazon s3 URL 可以安全共享吗?

ASP.NET(MVC): Which session timeout is what?

Apache 中的 PHP session

jakarta-ee - 有没有一种简单的方法可以使用标准查询来选择实体的 ID?

architecture - Java EE 中的分层架构

java - 如何子串和提取动态内容

java - 从 Java RNG 的范围中删除一个数字?

java - 用Java创建 "paint"应用程序

php - 在以 PHP 运行的 MySQL 文件中使用 PHP session 变量?

java - java.io.ObjectInputStream 类型无法解析。它是从所需的 .class 文件中间接引用的