有没有简单的方法来预处理和重定向GET请求?

时间:2011-09-03 17:21:50

标签: jsf authentication jsf-2 servlet-filters

我正在寻找最佳实践答案。我想为GET请求做一些预处理。所以例如如果不允许用户查看该页面,请将其重定向到另一页面。但我不想使用普通的servlet过滤器,因为我想在faces-config.xml中表达这种行为。这是可能的,如何调用,怎么做?

我可以定义一些也会返回一个String的Filter bean,告诉faces-config.xml下一步去哪里吗?

我用谷歌搜索了这个,但只打了正常的过滤器。如果我使用过滤器,@WebFilter可以同时成为@ManagedBean吗?还是那种糟糕的风格?

1 个答案:

答案 0 :(得分:18)

如果您在JSF之上进行HTTP请求身份验证,那么servlet过滤器确实是最好的方法。 JSF“只是”一个MVC框架,并且未指定JSF API中的任何内容来过滤传入的HTTP请求以检查用户身份验证。在正常的GET请求中,JSF托管bean通常仅在即将创建和发送HTTP响应时构建,或者可能已经提交。这不受托管bean内部的控制。如果响应已经提交,您将无法再更改(重定向)它。在即将发送响应之前,确实需要进行身份验证和更改请求/响应。

如果您不是homegrowing身份验证,那么您可以使用Java EE提供的容器管理身份验证,这将由<security-constraint>中的web.xml条目声明。请注意,这也与JSF分离,但它至少可以使您免于在家中生成servlet过滤器和托管bean。

一般方法是将受限制的页面分组为某个URL模式(如/app/*/private/*/secured/*等),并利用JSF存储会话范围的事实bean为HttpSession属性。想象一下,你有一个JSF会话作用域托管bean UserManager,它保存登录用户,然后你可以按如下方式检查它:

@WebFilter(urlPatterns={"/app/*"})
public class AuthenticationFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        HttpSession session = request.getSession(false);
        UserManager userManager = (session != null) ? (UserManager) session.getAttribute("userManager") : null;

        if (userManager == null || !userManager.isLoggedIn()) {
            response.sendRedirect(request.getContextPath() + "/login.xhtml"); // No logged-in user found, so redirect to login page.
        } else {
            chain.doFilter(req, res); // Logged-in user found, so just continue request.
        }
    }

    // ...
}

如果你使用的是JSF 2.2+,还有另一种方法可以在发送之前控制响应。您可以使用<f:viewAction>。在您的视图中放置以下内容:

<f:metadata>
    <f:viewAction action="#{authenticator.check}" />
</f:metadata>

@Named
@RequestScoped // Scope doesn't matter actually. The listener will always be called on every request.
public class Authenticator {

    public String check() {
        if (authenticated) {
            return null;
        }
        else {
            return "login?faces-redirect=true";
        }
    }

    // ...
}

保证在呈现响应之前触发。否则,当您在例如@PostConstruct,那么当响应已经部分呈现(并已提交)时,第一次创建bean时,您可能会冒java.lang.IllegalStateException: response already committed的风险。

在处理HTTP身份验证时,我不会认为它是一种“最佳”做法。它使它与JSF结合得太紧。你应该继续使用servlet过滤器。但出于其他目的,它可能没问题。

另见: