【问题标题】:Homegrown authentication filter does not show the welcome page本地验证过滤器不显示欢迎页面
【发布时间】:2013-05-14 21:26:20
【问题描述】:

所以我遇到了很多与我类似的问题,我开始明白了,直到我意识到我没有,简而言之,这就是故事:

在身份验证 bean 中,身份验证成功应该会导致访问一些 Web 资源,失败应该“过滤”访问并重定向到当前登录页面。 现在,在那个身份验证 bean 中,我添加了这一行以防成功:

FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(authentificationBean1.AUTH_STATE, "true") ;

AUTH_STATE 在 bean 中定义为:

public static final String AUTH_STATE = ""; 

如果失败,我会执行以下操作:

FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(authentificationBean1.AUTH_STATE, null) ;

现在在过滤器(应用于除身份验证页面之外的每个文件的过滤器)中,我的 doFilter 方法如下所示:

public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException {

        if (((HttpServletRequest) request).getSession().getAttribute(authentificationBean1.AUTH_STATE) == null) {
            ((HttpServletResponse) response).sendRedirect("authentification.xhtml");

        } 

        if(((HttpServletRequest) request).getSession().getAttribute(authentificationBean1.AUTH_STATE) != null) {
            ((HttpServletResponse) response).sendRedirect("accueil.xhtml");
        }

    }

我的想法是,如果身份验证顺利,authentificationBean1.AUTH_STATE 会话属性将设置为非空值,因此在过滤器测试中我将能够重定向到欢迎页面( accueil.xhtml) ;如果该属性为空,我们将留在身份验证页面。

品尝整个东西:过滤器似乎工作但太多了,我的意思是即使身份验证测试必须成功,它也不允许我通过欢迎页面。没有过滤器它实际上工作得很好,看起来我错过了一些关于使用带有 JSF 或过滤器的过滤器的东西。

P.S:没有应用 chain.doFilter 因为我没有另一个过滤器可以调用,但怀疑那里有什么东西。

感谢您的指示。

编辑:

<filter>
        <filter-name>RestrictionFilter</filter-name>
        <filter-class>beans.RestrictionFilter</filter-class>
</filter>
<filter-mapping>
        <filter-name>RestrictionFilter</filter-name>
        <url-pattern>/faces/accueil.xhtml</url-pattern>
</filter-mapping>

【问题讨论】:

  • 你能发布你的 web.xml 吗?
  • 没问题(抱歉迟到了),我会编辑我的初始帖子。
  • 我在这里做了几个 System.out,我现在注意到的是,当 AUTH_STATE 为空时,它没有被考虑在内,否则我得到了过滤器在其他情况下工作(其中 AUTH_STATE 不为空)。
  • 好的,刚刚注意到 - 我认为您只需要第一个条件 (.getAttribute(authentificationBean1.AUTH_STATE) == null)。第二个可能会导致无限循环。据我了解,第二个是针对经过身份验证的用户的情况,因此您不必将他/她重定向到任何地方。
  • 实际上,目前对我来说是 != null 条件。但我可以看到,如果失败,我不必重定向他......

标签: security jsf login servlet-filters


【解决方案1】:

您的过滤器在无限循环中运行,每次都重定向到它自己。它永远不会继续向 servlet 发出请求。您似乎误解了 HTTP 的工作原理。使用response.sendRedirect(),您基本上是在触发一个全新的HTTP 请求。这个全新的 HTTP 请求将再次调用过滤器。因此,当您的过滤器匹配条件以重定向到 accueil.xhtml 时,它将继续在无限循环中重定向到该页面,并且永远不会继续到 servlet 以处理请求。

此外,您还误解了chain.doFilter() 的含义。它没有明确地前进到下一个过滤器。它只是继续请求,就好像没有过滤器一样。链中是否有另一个过滤器完全无关紧要。如果没有过滤器,那么它只会出现在目标 servlet 中(在您的情况下是 FacesServlet,负责处理 JSF 页面)。

基本上,流程应该如下:

  • 如果用户未登录,则:
    • 如果当前请求的页面不是authentification.xhtml,则重定向到它。
    • 或者如果当前请求的页面已经是authentification.xhtml,那么继续请求。
  • 或者如果用户已登录,则继续请求而不管请求的页面。

换句话说,应该这样做:

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {    
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    HttpSession session = request.getSession(false);
    String loginURL = request.getContextPath() + "/authentification.xhtml";

    boolean loggedIn = session != null && session.getAttribute(authentificationBean1.AUTH_STATE) != null;
    boolean loginRequest = request.getRequestURI().startsWith(loginURL);
    boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER);

    if (loggedIn || loginRequest || resourceRequest)) {
        chain.doFilter(request, response);
    } else {
        response.sendRedirect(loginURL);
    }
}

请注意,我还添加了对 JSF 资源的检查(通过 &lt;h:outputStylesheet|outputScript|graphicImage&gt; 包含的 CSS/JS/图像文件),否则在显示登录页面时它们也会被阻止。另请注意,此过滤器可以映射到 /* 而不仅仅是单个页面。

【讨论】:

  • 无休止的循环,我没想到...所以每次我尝试访问“过滤”资源时都会启动过滤器,对吧?
  • 对每个匹配 URL 模式的 HTTP 请求调用过滤器。重定向指示客户端创建新的 HTTP 请求。基本上,您的过滤器一直在指示客户端创建一个新的 HTTP 请求。
  • 现在例如我已经将我的过滤器映射到 accueil.xhtml,这意味着每次调用该页面时过滤器都会干预“doFiltre”,不是吗?很抱歉坚持,读了几篇文章,但它们似乎只是在没有地下机制的情况下呈现代码,希望你能将我重定向到一些好的教程。
  • 没错。当 HTTP 请求与 URL 模式匹配时,将调用映射到 &lt;url-pattern&gt; 的过滤器。顺便说一下,servlet 也是如此,但是它们是在 过滤器之后调用的。因此,如果过滤器通过指示客户端创建新请求(重定向)来中止请求,它永远不会到达 servlet。当当前请求不需要重定向时,您应该使用 chain.doFilter() 继续当前请求。这正是我的回答所显示的。
  • 我明白了,谢谢,为我感谢 Chichiray,因为我认为他帮助您回答了这么多问题。
猜你喜欢
  • 2015-07-10
  • 2013-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-05
  • 2015-08-15
  • 2012-04-20
相关资源
最近更新 更多