Как выполнить запрос AJAX с проверкой подлинности без сброса времени ожидания сеанса Tomcat? - PullRequest
8 голосов
/ 29 января 2011

У меня есть существующее веб-приложение Grails, которое находится в производстве и имеет время ожидания сеанса 30 минут. Мы работаем с Tomcat (tcServer).

Когда пользователь проходит аутентификацию, и на определенных страницах я хочу периодически выполнять запросы ajax-запросов к серверу, которые не увеличивают этот 30-минутный тайм-аут сеанса, чтобы наш тайм-аут сеанса не был сорван.

Вопрос похож на на этот безответный вопрос asp.net , но ни один из ответов не подойдет, и это в области Java / Tomcat.

Как выполнить запрос AJAX с проверкой подлинности без сброса времени ожидания сеанса у кота?

Существует ли какой-нибудь механизм фильтрации или сопоставления URL-адресов, который я могу использовать, чтобы исключить запросы на увеличение времени ожидания сеанса?

Ответы [ 2 ]

4 голосов
/ 29 января 2011

Я бы пошел с фильтром Grails, который делает нечто похожее на то, что предлагает The-MeLLeR, без ненужного цикла во всех сеансах:

class AjaxTimeoutFilters {

   int sessionTimeout = 30 * 60 * 1000
   private static final String TIMEOUT_KEY = 'TIMEOUT_KEY'

   def filters = {
      all(controller:'*', action:'*') {
         before = {
            if (request.xhr) {
               Long lastAccess = session[TIMEOUT_KEY]
               if (lastAccess == null) {
                  // TODO
                  return false
               }
               if (System.currentTimeMillis() - lastAccess > sessionTimeout) {
                  session.invalidate()
                  // TODO - render response to trigger client redirect
                  return false
               }
            }
            else {
               session[TIMEOUT_KEY] = System.currentTimeMillis()
            }

            true
         }
      }
   }
}

Тайм-аут сеанса должен вводиться зависимостями или иным образом синхронизироваться со значением в web.xml.

Осталось две проблемы. Одним из них является случай, когда есть Ajax-запрос, но нет предыдущего не Ajax-запроса (lastAccess == null). Другой способ заключается в том, как перенаправить браузер на страницу входа в систему или куда вам нужно перейти, когда есть запрос Ajax после 30 минут без активности Ajax. Вам нужно будет обработать JSON или другой ответ, который клиент проверит, чтобы узнать, истек ли он, и выполнить перенаправление на стороне клиента.

0 голосов
/ 29 января 2011

Нет, невозможно ...

Один из следующих вариантов:

1) создайте javax.servlet.Filter и сохраните временную метку последнего (не-ajax) просмотра страницы в сеансе.

2) создайте javax.servlet.http.HttpSessionListener для хранения всех активных сессий.

3) использовать фоновый поток для аннулирования всех сеансов с истекшим сроком действия.


Пример кода:

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class LastAccessFilter implements Filter, HttpSessionListener {
    private static final Object SYNC_OBJECT = new Object();
    private static final String LAST_ACCESSED = "lastAccessed";
    private boolean backgroundThreadEnabled;

    public void destroy() {
        synchronized (SYNC_OBJECT){
            backgroundThreadEnabled = false;
            SYNC_OBJECT.notifyAll();
        }
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        if (req instanceof HttpServletRequest) {
            HttpServletRequest httpServletRequest = (HttpServletRequest) req;
            if(!isAjax(httpServletRequest)){
                httpServletRequest.getSession().setAttribute(LAST_ACCESSED, System.currentTimeMillis());
            }
        }
        chain.doFilter(req, resp);
    }
    public static boolean isAjax(request) {
       return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
    }   
    public void init(FilterConfig config) throws ServletException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (LastAccessFilter.this.backgroundThreadEnabled) {
                    synchronized (SYNC_OBJECT) {
                        try {
                            SYNC_OBJECT.wait(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        if (LastAccessFilter.this.backgroundThreadEnabled) {
                            HttpSession[] sessions;
                            synchronized (activeSessions){
                                sessions = activeSessions.toArray(new HttpSession[activeSessions.size()]);
                            }
                            cleanupInactiveSessions(sessions);
                        }
                    }
                }
            }

            private void cleanupInactiveSessions(HttpSession[] sessions) {
                for (HttpSession session : sessions) {
                    Object lastAccessedObject = session.getAttribute(LAST_ACCESSED);
                    if(lastAccessedObject == null) continue;
                    long lastAccessed = (Long)lastAccessedObject;
                    if(System.currentTimeMillis() > (lastAccessed + 1800000)){//30 Minutes
                        session.invalidate();
                    }
                }
            }
        });

        t.setDaemon(true);
        this.backgroundThreadEnabled = true;
        t.start();
    }

    private final List<HttpSession> activeSessions = new ArrayList<HttpSession>();

    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        synchronized (activeSessions) {
            this.activeSessions.add(httpSessionEvent.getSession());
        }
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        synchronized (activeSessions) {
            this.activeSessions.remove(httpSessionEvent.getSession());
        }
    }
}
...