会话到期时的授权重定向不适用于提交 JSF 表单,页面保持不变 [英] Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same

查看:24
本文介绍了会话到期时的授权重定向不适用于提交 JSF 表单,页面保持不变的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 JSF2.我已经实现了一个自定义的faces servlet,如下所示:

I am using JSF2. I have implemented a custom faces servlet like so:

public class MyFacesServletWrapper extends MyFacesServlet {
    // ...
}

其中我正在做一些授权检查并在用户未登录时发送重定向:

wherein I'm doing some authorization checks and sending a redirect when the user is not logged in:

public void service(ServletRequest request, ServletResponse response) {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;

    if (...) {
        String loginURL = req.getContextPath() + "/LoginPage.faces";
        res.sendRedirect(loginURL);
    }
}

这在用户尝试导航到另一个页面时起作用.但是,当通过 JSF 命令链接/按钮提交 JSF 表单时,这不起作用.sendRedirect() 行被命中并执行,没有抛出异常,但用户停留在同一页面.基本上,根本没有任何视觉变化.

This works when the user tries to navigate to another page. However, this does not work when a JSF form is submitted by a JSF command link/button. The line sendRedirect() line is hit and executed, no exception is been thrown, but the user stays at the same page. Basically, there's no visual change at all.

为什么这适用于页面导航,而不适用于表单提交?

Why does this work on page navigation, but not on form submit?

推荐答案

您的具体问题很可能是因为您的 JSF 命令链接/按钮实际上正在发送一个 ajax 请求,而该请求又期望一个特殊的 XML 响应.如果您发送重定向作为对 ajax 请求的响应,那么它只会将 ajax 请求重新发送到该 URL.这反过来会在没有反馈的情况下失败,因为重定向 URL 返回整个 HTML 页面而不是特殊的 XML 响应.您实际上应该返回一个特殊的 XML 响应,其中指示 JSF ajax 引擎更改当前的 window.location.

Your concrete problem is most likely caused because your JSF command link/button is actually sending an ajax request which in turn expects a special XML response. If you're sending a redirect as response to an ajax request, then it would just re-send the ajax request to that URL. This in turn fails without feedback because the redirect URL returns a whole HTML page instead of a special XML response. You should actually be returning a special XML response wherein the JSF ajax engine is been instructed to change the current window.location.

但实际上您遇到了更大的问题:在工作中使用了错误的工具.您应该使用 servlet 过滤器来完成这项工作,而不是使用自产的 servlet,当然也不能取代 FacesServlet 负责所有 JSF 工作.

But you've actually bigger problems: using the wrong tool for the job. You should use a servlet filter for the job, not a homegrown servlet and for sure not one which supplants the FacesServlet who is the responsible for all the JSF works.

假设您按如下方式在请求/视图范围的 JSF 支持 bean 中执行登录(如果您使用容器管理的身份验证,另请参阅 使用 j_security_check 在 Java EE/JSF 中执行用户身份验证):

Assuming that you're performing the login in a request/view scoped JSF backing bean as follows (if you're using container managed authentication, see also 2nd example of Performing user authentication in Java EE / JSF using j_security_check):

externalContext.getSessionMap().put("user", user);

那么这个过滤器的启动示例应该:

Then this kickoff example of a filter should do:

@WebFilter("/*") // Or @WebFilter(servletNames={"facesServlet"})
public class AuthorizationFilter implements Filter {

    private static final String AJAX_REDIRECT_XML = "<?xml version="1.0" encoding="UTF-8"?>"
        + "<partial-response><redirect url="%s"></redirect></partial-response>";

    @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() + "/login.xhtml";

        boolean loggedIn = (session != null) && (session.getAttribute("user") != null);
        boolean loginRequest = request.getRequestURI().equals(loginURL);
        boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER + "/");
        boolean ajaxRequest = "partial/ajax".equals(request.getHeader("Faces-Request"));

        if (loggedIn || loginRequest || resourceRequest)) {
            if (!resourceRequest) { // Prevent browser from caching restricted resources. See also https://stackoverflow.com/q/4194207/157882
                response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
                response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
                response.setDateHeader("Expires", 0); // Proxies.
            }

            chain.doFilter(request, response); // So, just continue request.
        }
        else if (ajaxRequest) {
            response.setContentType("text/xml");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().printf(AJAX_REDIRECT_XML, loginURL); // So, return special XML response instructing JSF ajax to send a redirect.
        }
        else {
            response.sendRedirect(loginURL); // So, just perform standard synchronous redirect.
        }
    }

    // ...
}

另见:

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆