JavaEE + Glassfishv3.0.1: потеря атрибута сеанса (SessionId не совпадает между запросами) - PullRequest
1 голос
/ 01 марта 2011

У меня есть home.jsf, который вызывает сервлет входа в систему, который просматривает базу данных и запрашивает объект user, используя имя пользователя и пароль. Затем я сохраняю этот user объект в сеансе под именем атрибута user, например 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");
    }

Затем у меня есть Filer, который сопоставляет все мои защищенные страницы, который будет пытаться извлечь объект пользователя из сеанса, в противном случае, перенаправьте меня на 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, но это происходит только тогда, когда я проверяю remember me. Так что теперь я нахожусь в CentralFeed.jsf, но тогда любой запрос, который я отправлю отсюда, вернется к home.jsf для повторного входа. Я иду через отладчик, поэтому при первом входе в систему, когда я впервые попадаю в Фильтр, я успешно извлекаю объект user из сеанса с помощью request.getSession().getAttribute("user");. Но после этого, когда я возвращаюсь в фильтр, у меня больше нет атрибута сеанса user. Я установил тайм-аут сеанса на 30 минут в своем файле web.xml

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

EDIT

Теперь, когда я распечатываю идентификатор сессии между запросами, это фактически другой идентификатор сессии, но я понятия не имею, почему? пожалуйста, помогите.

EDIT2

@ BalusC: Я действительно объявил сессию недействительной. Тогда вы покажете мне, как принудительно выйти из системы, когда пользователь входит в систему где-то еще (/2057152/kak-sdelat-nedeistvitelnym-seans-polzovatelya-kogda-on-dvazhdy-registriruetsya-s-odinakovymi-uchetnymi-dannymi). Итак, внутри объекта 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 я лишил законной силы сеанс, когда я закомментировал его, все работает. Я иду через отладчик, и вот что происходит. Когда я впервые захожу, LoginServlet его ловит Затем строка request.getSession().setAttribute("user", user); вызывает метод valueBound. Затем вызывается Фильтр, и строка chain.doFilter(req, res); снова вызывает метод valueBound, на этот раз session не равен нулю, поэтому он получает значения if и session.invalidate. Я комментирую сессию. Подтвердить, и она работает Но, как вы уже догадались, я не могу принудительно выйти из системы, когда пользователь входит в систему где-то еще. Видите ли вы очевидное решение для этого BalusC?

Ответы [ 2 ]

1 голос
/ 01 марта 2011

Сеанс HTTP поддерживается файлом cookie JSESSIONID.Убедитесь, что ваш Helper.COOKIE_NAME не использует то же имя файла cookie, что он переопределит файл cookie сеанса.

Если это не так, то я не знаю.Я бы использовал Firebug для отладки заголовков HTTP-запросов / ответов.В первом HTTP-ответе о новом сеансе вы должны увидеть заголовок Set-Cookie с файлом cookie JSESSIONID с идентификатором сеанса.Во всех последующих запросах в рамках одного сеанса вы должны видеть заголовок Cookie с файлом cookie JSESSIONID с идентификатором сеанса.

Новый сеанс будет создан, когда заголовок Cookie отсутствует или содержит файл cookie JSESSIONID с (для серверной части) несуществующим идентификатором сеанса (потому что он каким-то образом был признан недействительным) или когдасервер ответил новым заголовком Set-Cookie с другим идентификатором сеанса.Это должно помочь вам пригвоздить виновника.Это сервер, который сгенерировал новый сеансовый cookie?Или это клиент, который не отправил cookie-файл сеанса назад?

Если это был сервер, то где-то на стороне сервера сеанс истек / аннулирован.Попробуйте установить точку останова на HttpSession#invalidate(), чтобы закрепить ее дальше.

Если бы это был клиент (однако это было бы очень странно, поскольку, похоже, он хорошо поддерживает файлы cookie), попробуйте закодировать URL перенаправления навключите JSESSIONID.

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

Попробуйте с разными клиентами при необходимости исключить одного и другого.

1 голос
/ 01 марта 2011

посмотрите на параметр JSessionID в вашем запросе.Если он меняется, это означает, что вы теряете сеанс (браузер сообщает вашему серверу другой сеанс).Не знаю, почему это происходит, но, вероятно, это то, что вы делаете (откройте другое окно, измените контекст сервлета и вернитесь, измените сервер в каком-либо запросе ... и т.

...