JavaEE + Glassfishv3.0.1:丢失会话属性(请求之间SessionId不一样) [英] JavaEE + Glassfishv3.0.1: Losing session attribute (SessionId is not the same between request)

查看:100
本文介绍了JavaEE + Glassfishv3.0.1:丢失会话属性(请求之间SessionId不一样)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  protected void doPost(HttpServletRequest request, HttpServletResponse响应)
throws ServletException,IOException {
String username = request.getParameter(username);
String password = request.getParameter(password);
boolean remember =true.equals(request.getParameter(remember));
//使用SHA-256算法散列密码
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);
尝试{
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(回应,Helper.COOKIE_NAME,uuid,Helper.COOKIE_AGE);
} else {
//如果用户决定他们不想让我们记住它们
// //则删除与此用户有关的任何cookie
//表
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);
}

然后我有一个Filer映射到我所有的安全页面,从会话中检索用户对象,否则将我重定向到 home.jsf 再次登录

  public void doFilter(ServletRequest req,ServletResponse res,FilterChain chain)throws IOException,ServletException {
HttpServletRequest request =(HttpServletRequest)req;
HttpServletResponse响应=(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); //代理。
chain.doFilter(req,res);

$ / code>

现在您在这里看到了,我也操作了一些Cookie,但那是只有当我检查记住我时才会发生。所以现在我在 CentralFeed.jsf 中,但是我从这里发送的任何请求都会返回到 home.jsf 再次登录。我走过一个调试器,所以当我第一次登录时,第一次进入Filter时,我通过请求从会话中成功检索到用户对象。.getSession()的getAttribute( 用户); 。但在此之后,当我回到过滤器中时,我不再使用会话属性 user 了。我在web.xml中设置会话超时时间为30分钟。

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

编辑

<现在,当我在请求之间打印会话Id时,它实际上是不同的会话ID,但我不知道为什么?请帮助。


EDIT2
$ b @BalusC:我确实使会话无效。那时候,你向我展示了如何在用户登录到其他地方时强制注销(http://stackoverflow.com/questions/2372311/jsf-how-to-invalidate-an-user-session-when-he-logs-两次与最同credentia)。所以在User实体中,我有这个

  @Entity 
public class User实现Serializable,HttpSessionBindingListener {
@瞬态
私有静态映射< User,HttpSession> logins = new HashMap< User,HttpSession>();

@Override
public void valueBound(HttpSessionBindingEvent event){
HttpSession session = logins.remove(this);
if(session!= null){
session.invalidate(); //这是我无效会话
}
logins.put(this,event.getSession());
}

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




$ b $ valueBound
code>方法,我做了无效的会话,当我评论出来,一切正常。我走过调试器,这是发生了什么事。当我第一次登录时,LoginServlet会捕获它。然后,行 request.getSession()。setAttribute(user,user); 调用方法 valueBound 。然后过滤器被调用,并且行 chain.doFilter(req,res); 再次调用 valueBound 方法,这一次, session 不为null,所以它得到了if和 session.invalidate 。我评论session.invalidate和它的工作。但是,正如你可能猜测的那样,当用户在其他地方登录时,我无法强制登出。你看到这个BalusC的明显解决方案吗?

解决方案

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



如果情况并非如此,那么我不知道。我将使用Firebug来调试HTTP请求/响应头。在全新会话的第一个HTTP响应中,您应该看到带有 JSESSIONID cookie的 Set-Cookie 标头,会话ID。在同一会话中的所有后续请求中,您应该看到包含 JSESSIONID cookie的 Cookie 标头以及会话标识。

Cookie 标题不存在或包含 JSESSIONID时,将创建新会话(对于服务器端)不存在的会话ID(因为它以某种方式失效),或者当服务器使用新的 Set-Cookie 包含不同会话ID的标头。这应该可以帮助你打击罪魁祸首。它是生成新会话cookie的服务器吗?或者是客户没有发回会话cookie?



如果是服务器,那么在服务器端的某个地方,会话已经过期/失效。尝试在 HttpSession#invalidate()上设置一个断点,以便进一步细化它。

如果是客户端然而,这似乎很奇怪,因为它似乎支持cookies很好),然后尝试编码重定向URL以包含 JSESSIONID

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

如果需要,可以尝试使用不同的客户端来排除其他客户端。


I have a home.jsf that invoke a login servlet that look into database and query out the user object given the username and password. Then I save that user object into session under attribute name user, like this 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");
    }

Then I have a Filer that map to all my secured page, that will try to retrieve the user object from the session, otherwise, redirect me to home.jsf to login again

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);
    }

Now as you see here, I manipulate some Cookie as well, but that is only happen when I check remember me. So now I am in CentralFeed.jsf, but then any request that I send from here will bring back to home.jsf to login again. I walk through a debugger, so when I first login, the first time I get into the Filter, i successfully retrieve the user object from session by request.getSession().getAttribute("user");. But after that, when I get back in the filter, I no longer the session attribute user anymore. I set session timeout to be 30 min in my web.xml

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

EDIT

Now when I print out the session Id between request, it is fact different session id, but I have no idea why? please help.

EDIT2

@BalusC: I actually did invalidate the session. Back then, you show me how to force a logout when user log in somewhere else (http://stackoverflow.com/questions/2372311/jsf-how-to-invalidate-an-user-session-when-he-logs-twice-with-the-same-credentia). So inside User entity i have this

@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);
   }
}

In the valueBound method, I did invalidate the session, when I comment it out, everything work. I walk through the debugger, and here is what happen. When I first log in, the LoginServlet catch it. Then the line request.getSession().setAttribute("user", user); invoke the method valueBound. Then the Filter got called, and the line chain.doFilter(req, res); invoke the valueBound method again, this time, session is not null so it get in the if and session.invalidate. I comment the session.invalidate out and it work. But as u might have guess, I cant force a log out when user login somewhere else. Do you see a obvious solution for this BalusC?

解决方案

The HTTP session is maintained by the JSESSIONID cookie. Ensure that your Helper.COOKIE_NAME doesn't use the same cookie name, it will then override the session cookie.

If that is not the case, then I don't know. I would use Firebug to debug the HTTP request/response headers. In a first HTTP response on a brand new session you should be seeing the Set-Cookie header with the JSESSIONID cookie with the session ID. In all subsequent requests within the same session, you should be seeing the Cookie header with the JSESSIONID cookie with the session ID.

A new session will be created when the Cookie header is absent or contains a JSESSIONID cookie with a (for the server side) non-existing session ID (because it's been invalidated somehow), or when the server has responded with a new Set-Cookie header with a different session ID. This should help you in nailing down the culprit. Is it the server who generated a new session cookie? Or is it the client who didn't send the session cookie back?

If it was the server, then somewhere in the server side the session has been expired/invalidated. Try putting a breakpoint on HttpSession#invalidate() to nail it further down.

If it was the client (which would be very weird however, since it seems to support cookies fine), then try to encode the redirect URL to include the JSESSIONID.

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

Try with different clients if necessary to exclude the one and other.

这篇关于JavaEE + Glassfishv3.0.1:丢失会话属性(请求之间SessionId不一样)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆