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

Моя ситуация:

  1. У меня есть сервлет, который не должен быть доступен неавторизованным пользователям. Этот сервлет выполняет некоторую бизнес-логику и передает некоторые промежуточные данные в jsp secret.jsp через RequestDispatcher::forward(). (secret.jsp это просто пример, будет много сервлетов и/или jsps).

  2. Также есть логин jsp login.jsp.

  3. Перед сервлетом находится фильтр, который должен перенаправлять login.jsp все запросы от неавторизованных пользователей. В основном doFilter() выглядит так:

    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse resp = (HttpServletResponse) response;
    
    if(-1 == req.getRequestURI().indexOf("login.jsp")) {//if page which is not whitelisted
        HttpSession session = req.getSession(false);
        if(null == session) {
            RequestDispatcher rd = req.getServletContext().getRequestDispatcher("/login.jsp");
            rd.forward(request, response);
        }
        else {
            //not whitelisted but already logged in...
            log("we are logged in");
        }
    }
    
    chain.doFilter(request, response);
    

Проблемы

  1. Форвард в сервлете заставляет фильтр срабатывать 2 * 2 = 4 раза (дважды, потому что он движется вперед и назад, когда приходит запрос и когда доставляется ответ). Я хотел бы, чтобы он срабатывал только один раз (когда приходит первоначальный запрос) или, по крайней мере, только два раза.

  2. Сеанс запущен. Я не хочу, чтобы сеанс запускался до тех пор, пока пользователь не будет успешно аутентифицирован (т.е. отправит клиенту файл cookie JSESSIONID).

Каков самый элегантный способ исправить эти проблемы?

Я хотел бы не перенаправлять, отправляя браузеру заголовок Location, а вместо этого делать это внутри.

Дополнение

secret.jsp:

<%@page contentType="text/html" pageEncoding="UTF-8" import="java.util.*"%>
<%@taglib prefix="tags" uri="/WEB-INF/tlds/tag_library.tld" %>
<tags:wrapper title="hello world">
    hello ${requestScope.msg} 
</tags:wrapper>

который использует тег в wrapper.tagf:

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@tag pageEncoding="UTF-8"%>
<%@attribute name="title" required="true" type="java.lang.String" %>
<%@attribute name="menu" type="java.util.HashMap<String, Object>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <link rel="stylesheet" type="text/css" href="css/reset.css"/>
        <link rel="stylesheet/less" type="text/css" href="css/default.less"/>
        <script src="js/less-1.1.5.min.js" type="text/javascript"></script>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>${pageScope.title}</title>
    </head>
    <body>
        <div id="leftMenu">menu</div>
        <div id="body">
            <jsp:doBody/>
        </div>
    </body>
</html>

person Flavius    schedule 06.12.2011    source источник


Ответы (1)


Переадресация в сервлете приводит к тому, что фильтр срабатывает 2*2=4 раза (дважды, потому что он перемещается вперед и назад, когда приходит запрос и когда доставляется ответ). Я хотел бы, чтобы он срабатывал только один раз (когда поступает первоначальный запрос) или, по крайней мере, только два раза.

Вы забыли вернуться после переадресации, из-за чего ваш фильтр продолжал продолжать цепочку запросов/ответов.

rd.forward(request, response);
return;

Вызов произвольного метода Java, конечно же, не приводит к резкому завершению работающего в данный момент блока метода и выходу из него (кроме System#exit() или когда он выдает исключение, конечно, но это отдельная история).


Сеанс запущен. Я не хочу, чтобы сеанс запускался до тех пор, пока пользователь не будет успешно аутентифицирован (т. е. не будет отправлен файл cookie JSESSIONID клиенту).

Это вызвано где-то еще, кроме фильтра, скорее всего, вашим JSP. Добавьте следующее в начало вашего JSP, чтобы явно отключить неявное создание сеанса с помощью JSP:

<%@page session="false" %>

При необходимости создайте HttpSessionListener и поставьте точку останова на методе sessionCreated(), чтобы выявить настоящую первопричину.

person BalusC    schedule 06.12.2011
comment
Сделано, как было предложено, после доступа к TheServlet я все еще получаю JSESSIONID вместе с формой входа. - person Flavius; 07.12.2011
comment
почему jsp запускает сеанс без моего согласия? Я хочу контролировать это сам. - person Flavius; 07.12.2011
comment
@Flavius ​​Есть ли конкретная причина, по которой вы не хотите сеанса? Наличие одного не приносит (или очень, очень мало) вреда. В общем, проще проверить наличие известного атрибута сеанса в сеансе, чем пытаться вообще избежать сеанса. JSP создают сеанс, если вы явно не настроили их на это. - person Dave Newton; 07.12.2011
comment
Наличие сеанса без аутентифицированного пользователя мне не подходит. Семантически говоря. Кроме того, это сессия зря запущена, она просто загрязняет сервер. - person Flavius; 07.12.2011
comment
Кроме того, помог ли ответ в решении проблемы? Пожалуйста, дайте мне, если это все еще не решит проблему. - person BalusC; 07.12.2011