会话过期授权redirect在提交JSF表单时不起作用,页面保持不变

我正在使用JSF2。 我已经实现了一个自定义的面向servlet像这样:

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

其中我正在做一些授权检查,并在用户未login时发送redirect:

 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命令链接/button提交时,这不起作用。 sendRedirect()行被命中并执行,没有抛出exception,但用户停留在同一页面。 基本上,根本没有视觉上的变化。

为什么这个工作在页面导航,但不是在表单提交?

您的具体问题很可能是由于您的JSF命令链接/button实际上发送了一个ajax请求,而这个请求反过来期待一个特殊的XML响应。 如果您发送redirect作为对ajax请求的响应,那么它只是将ajax请求重新发送到该URL。 这反过来失败,没有反馈,因为redirectURL返回一个完整的HTML页面,而不是一个特殊的XML响应。 实际上,您应该返回一个特殊的XML响应,其中JSF ajax引擎已被指示更改当前的window.location

但是,你实际上遇到了更大的问题:使用错误的工具。 你应该使用一个servletfilter来处理这个作业,而不是一个本地的servlet,当然也不能使用一个代替负责所有JSF作品的FacesServlet

假设您在请求/视图范围的JSF支持bean中执行login,如下所示(如果您使用的是容器pipe理的身份validation,另请参阅使用j_security_check在Java EE / JSF中执行用户身份validation的第二个示例):

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

那么这个filter的开始的例子应该是:

 @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. } } // ... } 

也可以看看:

  • 使用JSF 2.0 / Facelets,有没有办法将全局侦听器附加到所有的AJAX调用?
  • FullAjaxExceptionHandler不会在ajaxbutton上显示会话过期的错误页面

。FacesContext.getCurrentInstance()getExternalContext()redirect( “newpage.xhtml”); 试试这个….代替res.sendredirect(cpath)。