1. 程式人生 > >基於的過濾器的登入驗證

基於的過濾器的登入驗證

問題背景

目前系統使用的基於攔截器Interceptor的登入驗證似乎出了些問題,有些情況下在Controller層獲取session中的使用者資料時失敗。具體原因沒有找到,組長說應該是Interceptor這塊出了些問題,於是打算將登入驗證放到Filter上去做。


基本業務邏輯

1 判斷請求url是否需要進行登入驗證;

2 如果需要登入驗證,則判斷是否有登入的使用者資料,否則執行過濾器鏈中的下一個過濾器;

3 如果使用者未登入,轉跳到登陸頁;否則執行過濾器鏈中的下一個過濾器


堆程式碼

package com.shtd.common.filter;

import java.io.IOException;
import java.util.regex.Pattern;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import com.shtd.common.util.LoginConstants;
import com.shtd.modules.edu.roll.entity.vo.StuUser;

public class LoginFilter extends OncePerRequestFilter{

	private String excludedPages;       
	private String[] excludedPageArray;   
	
	@Override
	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
//		System.out.println(" ==登入過濾==" + request.getServletPath());
		HttpSession session = request.getSession();
		StuUser curUser = (StuUser)session.getAttribute(LoginConstants.SESSION_KEY_CURUSER);
		if  (curUser == null || curUser.getId() ==  null){
//			System.out.println(" ==未通過==");
			response.sendRedirect(request.getContextPath()+ "/login");
		} else {
//			System.out.println(" ==通過==");
			filterChain.doFilter(request, response);
		}
	}
	
	/**
	 * 初始化時獲得引數
	 */
	@Override
	protected void initFilterBean() throws ServletException {
//		System.out.println("初始化 登入過濾器");
		excludedPages = getFilterConfig().getInitParameter("exclusions"); 
		if (StringUtils.isNotEmpty(excludedPages)) {     
			excludedPageArray = excludedPages.split(",");
			for (int i=0; i < excludedPageArray.length; i++) {
				String excludedPage = excludedPageArray[i];
				if (excludedPage.contains("**")){
					StringBuilder builder = new StringBuilder();
					builder.append("^");
					builder.append(StringUtils.replace(excludedPage, "**", "\\S*"));
					builder.append("$");
					excludedPageArray[i] = builder.toString();
				}
//				System.out.println(excludedPageArray[i]);
			}
		}
	}
	
	/**
	 * 是否要跳過過濾器
	 */
	protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
		if (excludedPageArray == null || excludedPageArray.length == 0) {
			return false;
		}
		String path = request.getServletPath();
		for (String excludedPage : excludedPageArray) {
			if (StringUtils.isBlank(excludedPage)) {
				continue;
			}
			if (excludedPage.startsWith("^")){
				if (Pattern.matches(excludedPage, path)) {
					return true;
				}
			} else if (excludedPage.equals(path)) {
				return true;
			}
		}
		return false;
	}

}

配置檔案

<!-- 登入狀態過濾 -->
            <filter>
                        <filter-name>loginFilter</filter-name>
                        <filter-class>com.shtd.common.filter.LoginFilter</filter-class>
                        <init-param>
                                    <param-name>exclusions</param-name>
                                    <param-value>/login,/init-pwd,/authenticate,/resources/**</param-value>
                        </init-param>
            </filter>

            <filter-mapping>
                        <filter-name>loginFilter</filter-name>
                        <url-pattern>/*</url-pattern>
            </filter-mapping>
            <!-- 登入狀態過濾, 結束-->


值得注意的點

1 Filter沒有類似於Interceptor的exclude-mapping的設定——嚴重覺得可能是我沒找到——只能通過init-param來傳入要忽略的路徑;

2 一般情況下,實現javax.servlet.Filter就行了,然後我發現繼承spring的OncePerRequestFilter會更方便一些。它將init和destroy方法都封裝好了,我們只需要關注於doFilter這塊。同時也提供和獲得傳入引數和是否需要進入過濾器的判斷方法,只要重寫相應的方法就行了

3 記得通過過濾後,執行filterChain.doFilter(request, response);


參考連結

Spring web過濾器-各種filter講解

Spring Mvc那點事---(19)Spring Mvc過濾器Filter實現登陸驗證