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

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

  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. Сессия началась. Я не хочу, чтобы сеанс запускался до тех пор, пока пользователь фактически не был успешно аутентифицирован (т.е. отправил куки-файл 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>

1 ответ

Решение

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

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

rd.forward(request, response);
return;

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


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

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

<%@page session="false" %>

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

Другие вопросы по тегам