前言
当用户访问我们的某些接口时,我们会去校验用户是否登录或者是用户是否有权限,比如我们一些管理员的功能就是不提供用户使用的。
这一系列的校验权限是很常用的,所以我们可以去配置SpringMVC拦截器,当用户访问我们的接口时,会自动的校验权限。
1.在SpringMVC中配置上我们的拦截器以及拦截的路径
/* 当面路径下的所有路径,不包含子文件夹
/** 指的是所有路径以及里面的子路径
/ web项目的根目录请求
2.配置我们的拦截器
首先在我们要在存放拦截器的路径下创建一个java类,随后使该类实现接口(HandlerInterceptor)并实现接口中的三个方法
2.1 preHandle() 拦截目标执行前,执行该方法。该方法有返回值(Boolean),若返回true则放行执行目标,若返回false则拦截不放行目标。
2.2 postHandle() 拦截目标执行后,执行该方法
2.3 afterCompletion() 拦截目标执行所有后,执行该方法
问题一:在拦截器的配置上,当我们需要注意拦截的时候别拦截到登录功能,当我们在进行管理员登录的时候,调用了管理员登录的接口。在调用的时候我们就被拦截器拦截了,此时我们还没登录就被拦截报错了。
所以我们应该想办法解决拦截登录的循环。
方法1:在springmvc配置文件中,编辑拦截器使之忽略拦截该路径
方法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"); } }
|