核心代碼:CheckLoginFilter
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.*;
public class CheckLoginFilter implements Filter {
protected FilterConfig filterConfig = null;
private String redirectURL = null; // 未登入重定向頁面(不含 ContextPath)
private List notCheckURLList = new ArrayList<>(); // 白名單 URL 列表
private String sessionKey = null; // Session 中存放用戶標識的鍵
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
HttpSession session = request.getSession();
// 未配置 sessionKey 直接放行
if (sessionKey == null) {
chain.doFilter(request, response);
return;
}
// 非白名單 且 Session 無用戶標識 → 重定向登入頁
if (!checkRequestURIIntNotFilterList(request) && session.getAttribute(sessionKey) == null) {
response.sendRedirect(request.getContextPath() + redirectURL);
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
notCheckURLList.clear();
}
/** 判斷當前請求 URI 是否在白名單中 */
private boolean checkRequestURIIntNotFilterList(HttpServletRequest request) {
String uri = request.getServletPath() +
(request.getPathInfo() == null ? "" : request.getPathInfo());
return notCheckURLList.contains(uri);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
redirectURL = filterConfig.getInitParameter("redirectURL");
sessionKey = filterConfig.getInitParameter("checkSessionKey");
String notCheckURLListStr = filterConfig.getInitParameter("notCheckURLList");
if (notCheckURLListStr != null) {
StringTokenizer st = new StringTokenizer(notCheckURLListStr, ";");
notCheckURLList.clear();
while (st.hasMoreTokens()) {
notCheckURLList.add(st.nextToken());
}
}
}
}
web.xml 配置範例
<filter>
<filter-name>CheckLoginFilter</filter-name>
<filter-class>com.example.filter.CheckLoginFilter</filter-class>
<init-param>
<param-name>checkSessionKey</param-name>
<param-value>currentUser</param-value> <!-- Session 屬性鍵 -->
</init-param>
<init-param>
<param-name>redirectURL</param-name>
<param-value>/login.jsp</param-value> <!-- 登入頁相對路徑 -->
</init-param>
<init-param>
<param-name>notCheckURLList</param-name>
<param-value>/login.jsp;/register.jsp;/static/;</param-value> <!-- 白名單,分號分隔 -->
</init-param>
</filter>
<filter-mapping>
<filter-name>CheckLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
設計亮點解析
| 特性 | 實現方式 |
| 配置外置化 | 所有關鍵參數透過 web.xml init-param 注入,無需改代碼。 |
| 白名單機制 | 支援靜態資源、登入頁、註冊頁等無需認證的路徑,分號分隔靈活擴展。 |
| Session 鍵可配置 | 適配不同業務對用戶標識的命名習慣(如 user、currentUser、token)。 |
| 路徑匹配精確 | 使用 getServletPath() + getPathInfo() 獲取完整請求路徑,避免漏攔截。 |
| 資源釋放 | destroy() 清空白名單列表,防止內存洩漏。 |
擴展建議
- 若專案使用 Spring,建議改用
HandlerInterceptor 或 Spring Security,功能更豐富。
- 白名單支援 Ant 風格通配符(如
/api/public/**)可引入 AntPathMatcher 增強匹配能力。
- 集群環境下 Session 共享需配合 Redis/Sticky Session 方案。