前言

当用户访问我们的某些接口时,我们会去校验用户是否登录或者是用户是否有权限,比如我们一些管理员的功能就是不提供用户使用的。
这一系列的校验权限是很常用的,所以我们可以去配置SpringMVC拦截器,当用户访问我们的接口时,会自动的校验权限。

1.在SpringMVC中配置上我们的拦截器以及拦截的路径

  /*   当面路径下的所有路径,不包含子文件夹

  /**   指的是所有路径以及里面的子路径

  /   web项目的根目录请求

 




spring mvc ip拦截 spring mvc拦截器配置_java


2.配置我们的拦截器

 首先在我们要在存放拦截器的路径下创建一个java类,随后使该类实现接口(HandlerInterceptor)并实现接口中的三个方法

  2.1 preHandle()             拦截目标执行前,执行该方法。该方法有返回值(Boolean),若返回true则放行执行目标,若返回false则拦截不放行目标。

  2.2 postHandle()      拦截目标执行后,执行该方法

  2.3 afterCompletion()   拦截目标执行所有后,执行该方法

 问题一:在拦截器的配置上,当我们需要注意拦截的时候别拦截到登录功能,当我们在进行管理员登录的时候,调用了管理员登录的接口。在调用的时候我们就被拦截器拦截了,此时我们还没登录就被拦截报错了。



spring mvc ip拦截 spring mvc拦截器配置_java_02


 所以我们应该想办法解决拦截登录的循环。

方法1:在springmvc配置文件中,编辑拦截器使之忽略拦截该路径


spring mvc ip拦截 spring mvc拦截器配置_java_03


方法2:在拦截器中加上逻辑判断,当拦截到的目标,是对应类中的对应方法时,放行

//解析HandlerMethod
String methodName = handlerMethod.getMethod().getName();
String className = handlerMethod.getBean().getClass().getSimpleName();
if(StringUtils.equals(className,"UserManageController") && StringUtils.equals(methodName,"login")){
    //如果是拦截到登录请求,不打印参数,因为参数里面有密码,全部会打印到日志中,防止日志泄露
    log.info("权限拦截器拦截到请求,className:{},methodName:{}",className,methodName);
    return true;
}

问题二: 在拦截器中我们统一设置了返回格式为Json,但是在我们产品的图片上传中有涉及到富文本上传,富文本的上传

返回值为Map形式,所以我们还需改进拦截器

解决方法:在返回值处细化返回内容。加入if判断

if(user ==null){
    if(StringUtils.equals(className,"ProductManageController") && StringUtils.equals(methodName,"richtextImgUpload")){
        Map resultMap = Maps.newHashMap();
        resultMap.put("success",false);
        resultMap.put("msg","请登录管理员");
        out.print(JsonUtil.obj2String(resultMap));
    }else {
        out.print(JsonUtil.obj2String(ServerResponse.createByErrorMessage("拦截器拦截,用户未登录")));
    }
}else{
    if(StringUtils.equals(className,"ProductManageController") && StringUtils.equals(methodName,"richtextImgUpload")){
        Map resultMap = Maps.newHashMap();
        resultMap.put("success",false);
        resultMap.put("msg","无权限操作");
        out.print(JsonUtil.obj2String(resultMap));
    }else {
        out.print(JsonUtil.obj2String(ServerResponse.createByErrorMessage("拦截器拦截,无权限操作")));
    }

}

注意:在做完拦截器后,修改原先Controller中的代码时,需注意保留图片上传到FTPServer中的功能,

拦截器代码:

@Slf4j
public class AuthorityInterceptor implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle");
        //请求中Controller中的方法名
        HandlerMethod handlerMethod = (HandlerMethod) handler;

        //解析HandlerMethod
        String className = handlerMethod.getBean().getClass().getSimpleName();//请求目标类名
        String methodName = handlerMethod.getMethod().getName();//请求目标方法名


        //解析参数,具体的参数key以及value是什么,打印日志
        StringBuffer requestParamBuffer = new StringBuffer();
        Map paramMap = request.getParameterMap();//获取请求参数Map

        //遍历Map,并且拼接成字符串
        Iterator iterator = paramMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry entry = (Map.Entry)iterator.next();
            String mapkey = (String)entry.getKey();
            String mapValue = StringUtils.EMPTY;

            //request这个参数的map(ParameterMap),里面的value返回的是一个String[]
            Object obj = entry.getValue();
            if(obj instanceof String[]){
                String[] strs = (String[])obj;
                mapValue = Arrays.toString(strs);
            }
            requestParamBuffer.append(mapkey).append("=").append(mapValue);

        }

        //放行管理员登录接口,避免登录循环
        if(StringUtils.equals(className,"UserManageController") && StringUtils.equals(methodName,"login")){
            //如果是拦截到登录请求,不打印参数,因为参数里面有密码,全部会打印到日志中,防止日志泄露
            log.info("权限拦截器拦截到请求,className:{},methodName:{}",className,methodName);
            return true;
        }

        //从Cookie中获取到登录的Token,然后去Redis中获取出来登录的用户
        User user = null;
        String loginToken = CookieUtil.readLoginToken(request);

        if(StringUtils.isNotEmpty(loginToken)){
            String userJsonStr = RedisShardedPoolUtil.get(loginToken);
            user = JsonUtil.string2Obj(userJsonStr,User.class);
        }

        //判断用户是否登录 || 是否为管理员
        if(user == null || (user.getRole().intValue() != Const.Role.ROLE_ADMIN) ){
            //返回false即不会调用controller里的方法
            //以下要更改返回值,首先重置response。
            response.reset();//这里要添加reset,否则报异常 getWriter() has already been called for this response.
            response.setCharacterEncoding("UTF-8");//由于response重置了,所以要重新设置编码,否则会乱码
            response.setContentType("application/json;charset=UTF-8");//由于response重置了,所以要重新设置返回值的类型,因为全部是json接口。

            PrintWriter out = response.getWriter();

            if(user ==null){
                out.print(JsonUtil.obj2String(ServerResponse.createByErrorMessage("拦截器拦截,用户未登录")));
            }else{
                out.print(JsonUtil.obj2String(ServerResponse.createByErrorMessage("拦截器拦截,无权限操作")));
            }
            out.flush();
            out.close();//这里要关闭流

            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        log.info("postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        log.info("afterCompletion");
    }
}