5

在我的 JSF 应用程序中,有一个Filter用于检查身份验证过程。当认证失败时,过滤器重定向到login.xhtml.

如何将 传递FacesMessage给我的登录页面Filter

虽然,我在下面使用过,但不行。

FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));

AuthenticationFilter.java

public class AuthenticationFilter implements Filter  {
    private FilterConfig config;
    private ServletContext servletContext;

    public void init(FilterConfig filterConfig) {
        config = filterConfig;
        servletContext = config.getServletContext();
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        HttpSession session = httpRequest.getSession();
        User user = (User) session.getAttribute(Constants.LOGIN_USER);
        if (user == null) {
            ...
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));

            String loginView = httpRequest.getContextPath() + Constants.LOGIN_PAGE;
            httpResponse.sendRedirect(loginView);
        } else if (!user.getRole().equals(Role.SYSTEM_ADMINISTRATOR)) {
            ....
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));

            String loginView = httpRequest.getContextPath() + Constants.LOGIN_PAGE;
            httpResponse.sendRedirect(loginView);
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
        servletContext.log("Exiting the filter");
    }

    public void destroy() {
        //Nothing to do.
    }
}
4

2 回答 2

10

FacesContextFacesServlet. _ 当您在过滤器中时,它还没有被调用。过滤器在 servlet 之前运行。因此,您永远无法FacesContext使用过滤器。另外,faces 消息是请求范围的,所以重定向会使它们消失。

让它login.xhtml在 a 期间自行设置<f:event type="preRenderView">。最简单的方法是让过滤器将其暂时放在会话范围内。

session.setAttribute("message", message);
httpResponse.sendRedirect(loginView);

然后,您在以下预渲染视图侦听器方法中将其从会话范围中删除login.xhtml

String message = (String) externalContext.getSessionMap().remove("message");

if (message != null) {
    context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
}
于 2012-12-21T05:22:26.867 回答
0

我在尝试在 EJB 计时器中获取 FacesContext 时遇到了类似的问题。BalusC 在多个线程上指出不可能做到这一点。或者,您可以使用“ServletContextListener”,但 ScheduledExecutorService 没有像 EJB 计时器那样定义调度。

在任何情况下,他提出的一个建议是实际向由托管 bean 支持的 JSF 发出 Web 请求,以利用我想用计时器设置的应用程序范围 bean 上的方法。

我提到这一点,因为您似乎可以做类似的事情,您可以将参数传递给 JSF 页面,其中包含您想要的消息和用户 IP 地址或其他内容。该页面可以由一个请求范围的 bean 支持,该 bean 中注入了一个应用程序范围的 bean,该 bean 将这些 bean 存储在以 IP 作为键的映射中。然后,当用户被重定向到登录页面时,该页面可以在请求范围的 bean 上调用获取错误消息方法,并将相同的应用程序范围的 bean 注入其中,从而获取该 IP 或类似内容的错误消息。

无论如何,我确信 BalusC 的答案是足够的,比这更合适,但是他的“只是从 ejb 计时器发出请求”的建议对我来说非常适合在应用程序范围的 bean 上调度方法调用,我想我可能会带来在这里增加它的可能用途。

@BalusC 你对我所指的帖子有任何想法吗?我找不到它。

于 2012-12-22T06:33:38.307 回答