1. 程式人生 > >springmvc的HandlerInterceptor的簡單了解(登錄例子)

springmvc的HandlerInterceptor的簡單了解(登錄例子)

java springmvc interceptor cookie 登錄

  • 抽象的類

  • package com.book.admin.interceptor;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.regex.Pattern;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    /**
     * 
     * @author liweihan
     *
     */
    public abstract class AbstractInterceptor implements HandlerInterceptor{
    	
    	private static Logger logger = LoggerFactory.getLogger(AbstractInterceptor.class);
    	
    	//不需要攔截的鏈接
    	protected static List<String> excludeActionList = new ArrayList<String>();
    	
    	static {
            excludeActionList.add("^/(login|static)(/)?(.+)?$");
            excludeActionList.add("^/(flush|test|site_map)(/)?(.+)?$");     //redis data flush
            excludeActionList.add("^/app/(flush|info.json|apkinfo.json)(/)?(.+)?$");    //前端接口http://m.tv.sohu.com/app
            excludeActionList.add("^/(hikeapp)(/)?(.+)?$");        //需要拉起客戶端的專輯數據訪問接口
            excludeActionList.add("^/(cooperation|activity|api|open|mobile|mb)(/)?(.+)?$");
            excludeActionList.add("^/(activity|api|open|mobile|mb)(/)?(.+)?$");
            excludeActionList.add("^/(test)(/)?(.+)?$");
    	}
    
    	public boolean preHandle(HttpServletRequest request,
    			HttpServletResponse response, Object handler) throws Exception {
    //		logger.debug(" ====== prehandle !");
    //		logger.info(" ======= URI:{}",request.getRequestURI());
    		request.setAttribute("uri", request.getRequestURI());//為了突出顯示選中的鏈接
    		for(String excludeUrl : excludeActionList) {
    			if(Pattern.matches(excludeUrl, request.getRequestURI())) {
    				return true;
    			}
    		}
    		return innerPreHandle(request, response, handler);
    	}
    	
    	protected abstract boolean innerPreHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    
    	public void postHandle(HttpServletRequest request,
    			HttpServletResponse response, Object handler,
    			ModelAndView modelAndView) throws Exception {
    //		logger.debug(" ====== postHandle !");
    	}
    
    	public void afterCompletion(HttpServletRequest request,
    			HttpServletResponse response, Object handler, Exception ex)
    			throws Exception {
    //		logger.debug(" ====== afterCompletion !");
    	}
    }


    2.權限過濾

    package com.book.admin.interceptor;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.regex.Pattern;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.lang.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.util.WebUtils;
    
    import com.book.core.model.AdminFunctions;
    import com.book.core.model.AdminRight;
    import com.book.core.model.User;
    import com.book.core.service.AdminFunctionsService;
    import com.book.core.service.AdminRightService;
    import com.book.core.utils.Constants;
    
    /**
     * 用戶權限過濾
     * @author liweihan
     *
     */
    public class FunctionsInterceptor extends AbstractInterceptor{
    	
    	private static Logger logger = LoggerFactory.getLogger(FunctionsInterceptor.class);
    	
    	@Autowired
    	private AdminRightService adminRightService;
    	@Autowired
    	private AdminFunctionsService adminFunctionsService;
    	
    	//登錄後不需要攔截的鏈接
    	protected static List<String> excludeActionList = new ArrayList<String>();
    	
    	static {
            excludeActionList.add("^/(index|admin/user|admin/myinfo)(/)?(.+)?$");
            excludeActionList.add("^/(book/del|book/detail.json|book/addorupdate)(/)?(.+)?$");
    	}
    
    	@Override
    	protected boolean innerPreHandle(HttpServletRequest request,
    			HttpServletResponse response, Object handler) throws Exception {
    		try {
    			User user = (User) WebUtils.getSessionAttribute(request, Constants.ADMIN_SESSION_USER_KEY);
    			if (user == null) {
    				response.sendRedirect("/login");
    				return false;
    			}
    			
    			//查找該用戶的權限
    			AdminRight adminRight = adminRightService.getObjByUserName(user.getName());
    			if (adminRight == null) {
    				return true;
    			}
    			
    			List<AdminFunctions> menus = null;
    			if (adminRight.getIsAdmin() == 1) {
    				menus = adminFunctionsService.getAll(); 
    				
    				request.setAttribute("menus", menus);
    				request.setAttribute("isAdmin", adminRight.getIsAdmin());
    				return true;
    			} else {
    				String right = adminRight.getRights();
    				if (StringUtils.isNotBlank(right)) {
    					String[] rs = right.split(",");
    					List<Integer> listId = null;
    					
    					if (rs != null && rs.length > 0) {
    						listId = new ArrayList<Integer>();
    						for (int i = 0; i < rs.length; i++) {
    							if (StringUtils.isNotBlank(rs[i])) {
    								listId.add(Integer.valueOf(rs[i]));
    							}
    						}
    					}
    					
    					//查詢
    					menus = adminFunctionsService.getObjByIds(listId);
    				}
    				for(String excludeUrl : excludeActionList) {
    					if(Pattern.matches(excludeUrl, request.getRequestURI())) {
    						request.setAttribute("menus", menus);
    						request.setAttribute("isAdmin", adminRight.getIsAdmin());
    						return true;
    					}
    				}
    				//對權限進行過濾,不能輸入URL就可以訪問
    				if (menus != null && menus.size() > 0) {
    					for(AdminFunctions adminFunctions : menus) {
    						if (request.getRequestURI().startsWith(adminFunctions.getUrl())) {
    							logger.info(" ====== request.getRequestURI():{},table-url:{}",request.getRequestURI(),adminFunctions.getUrl());
    							request.setAttribute("menus", menus);
    							request.setAttribute("isAdmin", adminRight.getIsAdmin());
    							return true;
    						}
    					}
    				}
    			}
    			response.sendRedirect("/login");
    			return false;
    		} catch (Exception e) {
    			logger.error(" ====== get AdminRight error!",e);
    			e.printStackTrace();
    		}
    		
    		return false;
    	}
    
    }

    3.登錄驗證

    package com.book.admin.interceptor;
    
    import java.net.URLEncoder;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.UUID;
    
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.util.WebUtils;
    
    import com.book.core.model.PersistentLogins;
    import com.book.core.model.User;
    import com.book.core.service.PersistentLoginsService;
    import com.book.core.service.UserService;
    import com.book.core.utils.Constants;
    import com.book.core.utils.CookieUtil;
    import com.book.core.utils.EncryptionUtil;
    
    
    /**
     * 登錄驗證攔截器
     * @author liweihan
     *
     */
    public class LoginInterceptor extends AbstractInterceptor{
    	
    	private static Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
    	@Autowired
    	private PersistentLoginsService persistentLoginsService;
    	@Autowired
    	private UserService userService;
    
    	@Override
    	protected boolean innerPreHandle(HttpServletRequest request,
    			HttpServletResponse response, Object handler) throws Exception {
    		
    		User user = (User) WebUtils.getSessionAttribute(request, Constants.ADMIN_SESSION_USER_KEY);
    		if (user != null) {
    			//已登錄
    			return true;
    		} else {
    			//從cookie中取值
    			Cookie cookie = CookieUtil.getCookie(request, Constants.RememberMe_Admin);
    			if (cookie != null) {
    				String cookieValue = EncryptionUtil.base64Decode(cookie.getValue());
    				String[] cValues = cookieValue.split(":");
    				if (cValues.length == 2) {
    					String userNameByCookie = cValues[0];//獲取用戶名
    					String uuidByCookie = cValues[1];//獲取UUID值
    					
    					//到數據庫中查詢自動登錄記錄
    					PersistentLogins pLogins  = persistentLoginsService.getObjByUUID(uuidByCookie);
    					if (pLogins != null) {
    						String savedToken = pLogins.getToken();
    						
    						//獲取有效時間
    						Date savedValidTime = pLogins.getValidTime();
    						Date currentTime = new Date();
    						
    						//如果還在有效期內,記錄判斷是否可以自動登錄
    						if (currentTime.before(savedValidTime)) {
    							User u = userService.getUserByName(userNameByCookie);
    							if (u != null) {
    								Calendar calendar = Calendar.getInstance();
    								calendar.setTime(savedValidTime);
    								
    								// 精確到分的時間字符串
    								String timeString = calendar.get(Calendar.YEAR) + "-" + calendar.get(Calendar.MONTH)
    										+ "-" + calendar.get(Calendar.DAY_OF_MONTH) + "-"
    										+ calendar.get(Calendar.HOUR_OF_DAY) + "-" + calendar.get(Calendar.MINUTE);
    								// 為了校驗而生成的密文
    								String newToken = EncryptionUtil.sha256Hex(u.getName() + "_" + u.getPassword() + "_"
    										+ timeString + "_" + Constants.salt);
    								
    								// 校驗sha256加密的值,如果不一樣則表示用戶部分信息已被修改,需要重新登錄
    								if (savedToken.equals(newToken)) {
    									//為了提高安全性,每次登錄之後都更新自動登錄的cookie值
    									String uuidNewString = UUID.randomUUID().toString();
    									String newCookieValue = EncryptionUtil.base64Encode(u.getName() + ":" + uuidNewString);
    									CookieUtil.editCookie(request, response, Constants.RememberMe_Admin, newCookieValue, null);
    									
    									//同時更新數據
    									pLogins.setSeries(uuidNewString);
    									pLogins.setUpdateTime(new Date());
    									persistentLoginsService.updateByObj(pLogins);
    									
    									//將用戶加到session中,不退出瀏覽器時只需要判斷session即可
    									WebUtils.setSessionAttribute(request, Constants.ADMIN_SESSION_USER_KEY, u);
    									
    									//校驗成功,此次攔截操作完成
    									return true;
    								} else {
    									//用戶信息部分被修改,刪除cookie並清空數據庫中的記錄
    									CookieUtil.delCookie(response, cookie);
    									persistentLoginsService.delObjById(pLogins.getId());
    								}
    							}
    						} else {
    							// 超過保存的有效期,刪除cookie並清空數據庫中的記錄
    							CookieUtil.delCookie(response, cookie);
    							persistentLoginsService.delObjById(pLogins.getId());
    						}
    					}
    				}
    			}
    			
    			try {
    				response.sendRedirect("/login?src=" + URLEncoder.encode(request.getRequestURI(), "UTF-8"));
    			} catch (Exception e) {
    				logger.error(" ===== loginInterceptor error ,url:{}{}",request.getRequestURL(),request.getRequestURI(),e);
    			} 
    			return false;
    		}
    	}
    
    }

    4.spring-mvc-servlet.xml的配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:mvc="http://www.springframework.org/schema/mvc" 
        xmlns:context="http://www.springframework.org/schema/context" 
        xsi:schemaLocation=" 
            http://www.springframework.org/schema/beans  
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
            http://www.springframework.org/schema/context  
            http://www.springframework.org/schema/context/spring-context-3.0.xsd 
            http://www.springframework.org/schema/mvc 
            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    	
    	<!-- 指定一個包讓其自動掃描 -->
    	<context:component-scan base-package="com.book.admin.controller"/>
    
    	<mvc:annotation-driven/>
    	
    	<!-- 下面註釋的部分表示:強調所有的請求都要經過springmvc框架 -->
        <mvc:default-servlet-handler/>
    	
    	<!-- 放行了以/static/開始的請求 -->
    	<mvc:resources location="/static/" mapping="/static/**"/> 
    	
    	<!-- 當一個方法完全是為了跳轉時,我們可以省略該方法,而在此寫一個配置就行了
    	<mvc:view-controller path="/index" view-name="index"/>
    	<mvc:view-controller path="/main" view-name="main"/>
    	<mvc:view-controller path="/success" view-name="success"/> 
    	<mvc:view-controller path="/index" view-name="main"/>
    	<mvc:view-controller path="/" view-name="main"/> 
    	<mvc:view-controller path="/admin/myinfo" view-name="myinfo"/>-->
    	<!-- 
    	<mvc:view-controller path="/book" view-name="book"/>
    	 -->
    	
    	<mvc:interceptors>
    		<bean class="com.book.admin.interceptor.LoginInterceptor"></bean>
    		<bean class="com.book.admin.interceptor.FunctionsInterceptor"></bean>
    		<!--  
    		<mvc:interceptor>  
    	        <mvc:mapping path="/test/number.do"/>  
    	        <bean class="com.host.app.web.interceptor.LoginInterceptor"/>  
    	    </mvc:interceptor>  
    	    -->
    	</mvc:interceptors>
    	
    	<!-- 配置springmvc的視圖解析器 -->
    	<bean id="viewResolver" 
    		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    		<property name="suffix" value=".jsp"/>
    		<property name="prefix" value="/WEB-INF/views/"/>
    	</bean>
    	
    	<!-- 文件上傳解析器   -->
    	<bean id="multipartResolver" 
    	    class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 
    	    <property name="maxUploadSize" value="100000"/> 
    	</bean>
    </beans>

    參考:

    攔截器的基礎了解

    http://blog.csdn.net/sunp823/article/details/51694662


    攔截器的詳細了解

    http://jinnianshilongnian.iteye.com/blog/1670856


    登錄例子的思路了解

    http://blog.51cto.com/983836259/1880284


    正則表達式

    http://www.cnblogs.com/sparkbj/articles/6207103.html


    springmvc的攔截器和過濾器的區別

    http://blog.csdn.net/xiaoyaotan_111/article/details/53817918


    java Web中的過濾器Filter和interceptor的理解

    http://www.jianshu.com/p/39c0cfe25997


    springmvc的HandlerInterceptor的簡單了解(登錄例子)