Spring MVC 使用拦截器优雅地实现权限验证功能

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

原文地址:https://www.cnblogs.com/yhtboke/p/5749071.html