如何过滤未经验证的用户并在不启动会话的情况下显示登录表单?

时间:2011-12-06 20:31:00

标签: jsp servlets servlet-filters

我的情况是:

  1. 我有一个servlet,未经过身份验证的用户无法访问。此servlet执行一些业务逻辑,并通过secret.jsp将一些中间数据传递给jsp RequestDispatcher::forward()。 (secret.jsp只是一个例子,会有很多servlet和/或jsps)。

  2. 还有一个登录jsp login.jsp

  3. 在servlet前面有一个过滤器,它应该重定向到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);
    
  4. 问题是

    1. servlet中的转发使得过滤器被触发2 * 2 = 4次(两次,因为它来回传递,因为请求进入,并且响应被传递)。我希望它只被触发一次(当初始请求进入时) - 或者至少只触发两次。

    2. 会话已启动。我不希望在用户实际上未成功通过身份验证之前启动会话(即将JSESSIONID cookie发送到客户端)。

    3. 解决这些问题最优雅的方法是什么?

      我不想通过向浏览器发送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 个答案:

答案 0 :(得分:0)

  

servlet中的转发使得过滤器被触发2 * 2 = 4次(两次,因为它来回传递,因为请求进入,并且响应被传递)。我希望它只被触发一次(当初始请求进入时) - 或者至少只触发两次。

您忘记了在前进后返回,这导致您的过滤器仍然继续请求/响应链。

rd.forward(request, response);
return;

调用任意Java方法肯定不会突然终止当前正在运行的方法块并跳出它(期望System#exit()或当它抛出异常当然,但这是一个故事)< / em>的


  

会话已启动。我不希望在用户实际上没有成功通过身份验证之前启动会话(即将JSESSIONID cookie发送到客户端)。

这是在过滤器之外的其他地方引起的,很可能是由JSP引起的。将以下内容添加到JSP的顶部以显式禁用JSP的隐式会话创建:

<%@page session="false" %>

如有必要,创建一个HttpSessionListener并在sessionCreated()方法上设置一个断点,以实现真正的根本原因。