SpringMVC拦截器的配置及应用

前言

当用户访问我们的某些接口时,我们会去校验用户是否登录或者是用户是否有权限,比如我们一些管理员的功能就是不提供用户使用的。
这一系列的校验权限是很常用的,所以我们可以去配置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");
}
}

 

 


posted @ 2021-01-27 17:37  _kerry  阅读(757)  评论(0编辑  收藏  举报