您需要实施javax.servlet.Filter http://docs.oracle.com/javaee/6/api/javax/servlet/Filter.html课堂上,做所需的工作doFilter()
方法并将其映射到覆盖受限页面的 URL 模式上,/user/*
或许?在 - 的里面doFilter()
您应该以某种方式检查会话中登录用户的存在。此外,您还需要考虑 JSF ajax 和资源请求。 JSF ajax 请求需要特殊的 XML 响应才能让 JavaScript 执行重定向。需要跳过 JSF 资源请求,否则您的登录页面将不再有任何 CSS/JS/图像。
假设你有一个/login.xhtml
将登录用户存储在 JSF 托管 bean 中的页面externalContext.getSessionMap().put("user", user)
,那么你可以通过session.getAttribute("user")
通常的方式如下:
@WebFilter("/user/*")
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.
}
}
// You need to override init() and destroy() as well, but they can be kept empty.
}
此外,该过滤器还禁用了安全页面上的浏览器缓存,因此浏览器后退按钮将不再显示它们。
如果您碰巧使用 JSF 实用程序库OmniFaces http://omnifaces.org,上面的代码可以减少如下:
@WebFilter("/user/*")
public class AuthorizationFilter extends HttpFilter {
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, HttpSession session, FilterChain chain) throws ServletException, IOException {
String loginURL = request.getContextPath() + "/login.xhtml";
boolean loggedIn = (session != null) && (session.getAttribute("user") != null);
boolean loginRequest = request.getRequestURI().equals(loginURL);
boolean resourceRequest = Servlets.isFacesResourceRequest(request);
if (loggedIn || loginRequest || resourceRequest) {
if (!resourceRequest) { // Prevent browser from caching restricted resources. See also https://stackoverflow.com/q/4194207/157882
Servlets.setNoCacheHeaders(response);
}
chain.doFilter(request, response); // So, just continue request.
}
else {
Servlets.facesRedirect(request, response, loginURL);
}
}
}
也可以看看:
- 我们的 Servlet 过滤器 wiki 页面 https://stackoverflow.com/tags/servlet-filters/info
- 如何处理数据库中用户的身份验证/授权? https://stackoverflow.com/questions/9965708/how-to-handle-authentication-authorization-with-users-in-a-database
- 使用 JSF 2.0 / Facelets,有没有办法将全局侦听器附加到所有 AJAX 调用? https://stackoverflow.com/questions/9305144/using-jsf-2-0-facelets-is-there-a-way-to-attach-a-global-listener-to-all-ajax/
- 避免 JSF Web 应用程序上的后退按钮 https://stackoverflow.com/questions/10305718/avoid-back-button-on-jsf-web-application
- JSF:如何控制 JSF 中的访问和权限? https://stackoverflow.com/questions/12516349/jsf-how-control-access-and-rights-in-jsf