在上一篇 SpringAOP 實現功能權限校驗功能 中雖然用AOP通過拋異常,請求轉發等勉強地實現了權限驗證功能,但感覺不是那么完美,應該用攔截器來實現才是最佳的,因為攔截器就是用來攔截請求的,在請求層面進行權限驗證是最好的時機。
假設下面的請求需要進行權限驗證,在請求中通過參數params指定必須帶有Helper.PARAM_FUNCTION_ID參數,這樣攔截器通過判斷是否帶有該參數,如果帶有則進行權限驗證,否則不作處理。
@RequestMapping(value = "/moduleAccess.do",params=Helper.PARAM_FUNCTION_ID, method = RequestMethod.POST, produces="text/html;charset=utf-8") @ResponseBody public String moduleAccess(String action,FrmModule module) { int rs = -1; try{ if(Helper.F_ACTION_CREATE.equals(action)){ rs = moduleService.access(module,Helper.DB_ACTION_INSERT); //module.setModuleid(rs); module = moduleService.selectByPrimaryKey(rs); }else if(Helper.F_ACTION_EDIT.equals(action)){ rs = moduleService.access(module,Helper.DB_ACTION_UPDATE); module = moduleService.selectByPrimaryKey(module.getModuleid()); }else if(Helper.F_ACTION_REMOVE.equals(action)){ rs = moduleService.access(module,Helper.DB_ACTION_DELETE); }else{ return JSON.toJSONString(new Result(false,"請求參數錯誤:action")); } }catch(Exception e){ e.printStackTrace(); return JSON.toJSONString(new Result(false,"操作失敗,出現異常,請聯系管理員!")); } if(rs<0){ return JSON.toJSONString(new Result(false,"操作失敗,請聯系管理員!")); } return JSON.toJSONString(new Result(true,module)); }
那么對應的攔截器就直接用登錄驗證的那個攔截器即可,SecurityInterceptor
package com.jykj.demo.filter; import java.io.PrintWriter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import com.alibaba.fastjson.JSON; import com.jykj.demo.entity.SysUser; import com.jykj.demo.service.SysUserRolePermService; import com.jykj.demo.util.Helper; import com.jykj.demo.util.Result; /** * 1.此攔截器用於攔截所有請求,用於登錄權限驗證 * 2.攔截 帶 moduleId 參數的請求,在渲染視圖之前返回 模塊權限值 * @author Administrator * */ public class SecurityInterceptor implements HandlerInterceptor{ @Autowired SysUserRolePermService sysUserRolePermService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("SecurityInterceptor preHandle:"+request.getContextPath()+","+request.getRequestURI()+","+request.getMethod()); HttpSession session = request.getSession(); if (session.getAttribute(Helper.SESSION_USER) == null) { System.out.println("AuthorizationException:未登錄!"+request.getMethod()); if("POST".equalsIgnoreCase(request.getMethod())){ response.setContentType("text/html; charset=utf-8"); PrintWriter out = response.getWriter(); out.write(JSON.toJSONString(new Result(false,"未登錄!"))); out.flush(); out.close(); }else{ response.sendRedirect(request.getContextPath()+"/login"); } return false; } else { Object obj = request.getParameter(Helper.PARAM_FUNCTION_ID); if(obj==null) return true;//沒有帶功能參數不需要驗證 int functionId = Integer.parseInt(obj.toString()); String rs = sysUserRolePermService.permissionValidate(functionId); System.out.println("校驗結果:"+rs); if(rs.trim().isEmpty()){ return true;//正常通過 }else{ response.setContentType("text/html; charset=utf-8"); PrintWriter out = response.getWriter(); out.write(JSON.toJSONString(new Result(false,rs))); out.flush(); out.close(); return false; } } } //模塊權限值 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { /* Object obj = request.getParameter(Helper.PARAM_MODULE_ID); System.out.println(Helper.PARAM_MODULE_ID+":"+obj); if(obj == null) return;//如果沒有moduleId 參數,否則什么都不做,否則返回模塊權限值 System.out.println("SecurityInterceptor postHandle:"+request.getContextPath()+","+request.getRequestURI()+","+request.getMethod()); SysUser loginUser = (SysUser)request.getSession().getAttribute(Helper.SESSION_USER); int value = sysUserRolePermService.getModulePerm(loginUser.getUserid(),Integer.parseInt(obj.toString())); modelAndView.addObject(Helper.MVALUE,value); */ } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
攔截器配置不變
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/*"/> <!-- 攔截/ /test /login 等等單層結構的請求 --> <mvc:mapping path="/**/*.aspx"/><!-- 攔截后綴為.aspx的請求 --> <mvc:mapping path="/**/*.do"/><!-- 攔截后綴為 .do的請求 --> <mvc:exclude-mapping path="/login"/> <mvc:exclude-mapping path="/signIn"/> <mvc:exclude-mapping path="/register"/> <bean class="com.jykj.demo.filter.SecurityInterceptor"> </bean> </mvc:interceptor> </mvc:interceptors>
這樣即實現了對某個功能的權限校驗的功能
客戶端發送 /moduleAccess.do 請求,該請求帶有參數Helper.PARAM_FUNCTION_ID,其值為某個功能的id
然后攔截器攔截該請求,判斷出帶有該參數,則對其進行權限校驗,如果未通過,寫response給客戶端,格式是json的字符串,並返回false表示請求已由本攔截器處理了,不會往下執行(返回true表示正常往下執行)。這樣就達到了權限驗證的目的。這是相對更優雅的實現方式,最起碼比上一篇講的用AOP來實現更優雅。
另外攔截器的postHandle方法是在控制器執行結束,頁面渲染之前執行的,所以可以用來給頁面添加或修改model屬性。