在上一篇 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属性。