在JSF 2应用中结合会话变量使用Servlet Filter的咨询
嘿,我来帮你搞定这个Servlet Filter结合JSF会话的实现!你已经在登录时把userid存到会话里了,接下来只需要完善Filter的核心逻辑,再做好配置就行,具体步骤如下:
实现JSF会话结合Servlet Filter的权限控制方案
一、完善Filter的核心逻辑(doFilter方法)
Filter的核心是doFilter方法,这里我们要做的就是检查会话中的userid是否存在,以此判断用户是否已登录,再决定放行请求还是重定向到登录页。
注意:不要在Filter里用JSF的FacesContext,因为Filter是Servlet层组件,执行时机早于JSF上下文的初始化,直接用Servlet的HttpSession更可靠。
完整的Filter代码如下:
import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebFilter(urlPatterns = "*.xhtml") // 先加上注解,后面会讲配置细节 public class PageFilter implements Filter { private FilterConfig filterConfig; @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 转换为HTTP请求/响应对象,方便操作会话和重定向 HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; // 从会话中获取你登录时存储的userid String userId = (String) httpRequest.getSession().getAttribute("userid"); // 定义不需要拦截的路径:登录页、JSF自带的静态资源(比如css/js) String requestURI = httpRequest.getRequestURI(); boolean isLoginPage = requestURI.contains("/login.xhtml"); boolean isStaticResource = requestURI.contains("/javax.faces.resource/"); // 核心判断逻辑 if (userId == null && !isLoginPage && !isStaticResource) { // 未登录且访问的是受保护页面,重定向到登录页 httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.xhtml"); } else { // 已登录或访问的是允许路径,放行请求 chain.doFilter(request, response); } } @Override public void destroy() { // 若有资源需要清理,在这里处理,比如关闭连接等 } }
二、Filter的配置方式(两种可选)
方式1:注解配置(Servlet 3.0+推荐)
直接在Filter类上添加@WebFilter注解,指定要拦截的URL模式。比如上面代码里的@WebFilter(urlPatterns = "*.xhtml"),表示拦截所有JSF页面请求。
如果需要更精细的拦截规则,比如只拦截某个目录下的页面:
@WebFilter(urlPatterns = {"/secured/*", "*.xhtml"})
方式2:web.xml配置(兼容老版本Servlet)
如果你的项目用的是Servlet 3.0以下版本,或者需要更灵活的配置,可以在web.xml中添加以下内容:
<filter> <filter-name>PageFilter</filter-name> <filter-class>com.yourpackage.PageFilter</filter-class> <!-- 替换成你的Filter全类名 --> </filter> <filter-mapping> <filter-name>PageFilter</filter-name> <url-pattern>*.xhtml</url-pattern> <!-- 拦截所有JSF页面 --> <servlet-name>FacesServlet</servlet-name> <!-- 也可以直接拦截JSF核心Servlet --> </filter-mapping>
三、额外注意事项
- 避免循环重定向:一定要把登录页排除在拦截范围外,否则用户未登录时会一直被重定向到登录页,导致死循环。
- 处理AJAX请求:如果你的页面用了JSF AJAX(比如
<h:commandButton ajax="true" />),普通重定向不会生效,因为AJAX请求期望的是JSF的部分响应。可以修改重定向逻辑:if (userId == null && !isLoginPage && !isStaticResource) { String loginUrl = httpRequest.getContextPath() + "/login.xhtml?faces-redirect=true"; // 判断是否是AJAX请求 if ("partial/ajax".equals(httpRequest.getHeader("Faces-Request"))) { // 返回JSF AJAX专用的重定向响应 httpResponse.setContentType("text/xml"); httpResponse.getWriter().write("<?xml version='1.0' encoding='UTF-8'?>"); httpResponse.getWriter().write("<partial-response><redirect url='" + loginUrl + "'></redirect></partial-response>"); } else { // 普通请求直接重定向 httpResponse.sendRedirect(loginUrl); } } - 会话过期处理:当会话过期时,
userid会变为null,Filter会自动拦截并重定向到登录页,正好符合需求。
内容的提问来源于stack exchange,提问作者Diaboliko
相关产品推荐
相关产品推荐

