[TOC]

本文目的

学习和记录SpringBoot项目中如何配置拦截器,以及如何使用拦截器机型权限控制。

拦截器

​ 拦截器主要用来拦截各种请求并在拦截器中进行相应的处理,一般情况下用来进行权限校验,拦截登录转发,统一日志打印等操作。

​ 拦截器有两种形式:

  1. 实现HandlerInterceptor
  2. 继承HandlerInterceptorAdapter

使用场景

利用拦截器对多个菜单进行权限控制,只有勾选指定权限的人才能够查看该列表全部数据,其他的必须数据某限定条件才能够进行查询。

考虑到如果在每个菜单控制器中对参数和指定权限进行过滤和控制的话,改动文件太多并且重复代码太多,所以使用拦截器对指定路径的请求进行拦截,在拦截器中记性统一处理,那么只在新增加的类中操作就能实现所有指定菜单的权限控制。

实现代码

自定义拦截器类

实现HandlerInterceptor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//交给Spring管理
@Component
//日志打印
@Slf4j
public class QueryBlackControlInterceptor implements HandlerInterceptor {

/**
* @Description: 控制校验是否拥有查看全部的权限,没有则必须携带指定参数访问
* @Description: 在进入控制器前执行此操作
* @param request
* @param response
* @param handler
* @return boolean
* @author Surpass
* @date 2020/12/8 18:01
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
log.info("黑名单权限校验拦截器");
log.info("request请求地址path[{}] uri[{}] url[{}]", request.getServletPath(),
request.getRequestURI(),request.getRequestURL());
Subject subject = SecurityUtils.getSubject();
//是否具有查看全部的权限
boolean blacklistMenuControl = subject.isPermitted("queryALLBlack:view");
log.info("是否存在查看全部的权限:{}",blacklistMenuControl);

if (!blacklistMenuControl){
//没有权限判断是否存在指定的查询条件
//返回路径
String url = null;
//提示语
String alert = null;
Map<String, String[]> parameterMap = request.getParameterMap();
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();

//匹配黑名单菜单
for (Map.Entry<String, String[]> entry : entries) {
String key = entry.getKey();
String[] value = entry.getValue();
if (Objects.equals(key, "phone")){
if (StringUtils.isBlank(value[0])){
url = "/phoneBlack/getPhoneBlack";
alert = "请输入手机号";
}
break;
}
if (Objects.equals(key, "idCardNum")){
if (StringUtils.isBlank(value[0])){
url = "/idCardNumBlack/getIdCardNumBlack";
alert = "请输入身份证号";
}
break;
}

//是否存在需要返回的内容
if (StringUtils.isNotBlank(url) && StringUtils.isNotBlank(alert)) {
log.info("黑名单查询校验不通过");
response.setContentType("text/html; charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<script language='javascript'>");
writer.println("window.location.href = '"+url+"';");
writer.println("alert('"+alert+"');");
writer.println("</script>");
return false;
}
}
log.info("黑名单权限通过");
return true;
}

/**
* @Description: 在执行完控制器之后,视图渲染之前执行此操作
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

}

/**
* @Description: 在试图渲染之后执行此操作
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {

}
}

继承HandlerInterceptorAdapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//交给Spring管理
@Component
//日志打印
@Slf4j
public class QueryBlackControlInterceptor implements HandlerInterceptor {

/**
* @Description: 控制校验是否拥有查看全部的权限,没有则必须携带指定参数访问
* @Description: 在进入控制器前执行此操作
* @param request
* @param response
* @param handler
* @return boolean
* @author Surpass
* @date 2020/12/8 18:01
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
log.info("黑名单权限校验拦截器");
log.info("request请求地址path[{}] uri[{}] url[{}]", request.getServletPath(),
request.getRequestURI(),request.getRequestURL());
Subject subject = SecurityUtils.getSubject();
//是否具有查看全部的权限
boolean blacklistMenuControl = subject.isPermitted("queryALLBlack:view");
log.info("是否存在查看全部的权限:{}",blacklistMenuControl);

if (!blacklistMenuControl){
//没有权限判断是否存在指定的查询条件
//返回路径
String url = null;
//提示语
String alert = null;
Map<String, String[]> parameterMap = request.getParameterMap();
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();

//匹配黑名单菜单(只需要在这里根据菜单返回不同的信息和路径就可以了)
for (Map.Entry<String, String[]> entry : entries) {
String key = entry.getKey();
String[] value = entry.getValue();
if (Objects.equals(key, "phone")){
if (StringUtils.isBlank(value[0])){
url = "/phoneBlack/getPhoneBlack";
alert = "请输入手机号";
}
break;
}
if (Objects.equals(key, "idCardNum")){
if (StringUtils.isBlank(value[0])){
url = "/idCardNumBlack/getIdCardNumBlack";
alert = "请输入身份证号";
}
break;
}

//是否存在需要返回的内容
if (StringUtils.isNotBlank(url) && StringUtils.isNotBlank(alert)) {
log.info("黑名单查询校验不通过");
response.setContentType("text/html; charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<script language='javascript'>");
writer.println("window.location.href = '"+url+"';");
writer.println("alert('"+alert+"');");
writer.println("</script>");
return false;
}
}
log.info("黑名单权限通过");
return true;
}
}

说明:这里对权限控制只需要用到 preHandle 就可以了,所以选择继承的方式完成。

自定义拦截器配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
public class QueryBlackControlConfig extends WebMvcConfigurerAdapter {

//注入拦截器类
@Autowired
private QueryBlackControlInterceptor queryBlackControlInterceptor;

/**
* @Description: 拦截菜单权限控制路径(拦截菜单很多,这里举两个例子)
* @param registry
* @return void
* @throws
* @author Surpass
* @date 2020/12/8 17:59
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//可变参数长度(需要被拦截的请求路径)
//将拦截器类注册到配置中
registry.addInterceptor(queryBlackControlInterceptor).addPathPatterns(
"/phoneBlack/getPhoneBlackList",
"/idCardNumBlack/getIdCardNumBlackList");
}
}

查看结果

本地测试进行三次请求(1.没有权限,没有参数、2.没有权限,有参数、3.有权限,没有参数)

1
http://127.0.0.1:8111/phoneBlack/getPhoneBlackList

控制台打印结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
INFO 2020-12-15 16:23:04.440 黑名单权限校验拦截器
INFO 2020-12-15 16:23:04.440 request请求地址url[http://127.0.0.1:8111/phoneBlack/getPhoneBlackList]
INFO 2020-12-15 16:23:04.451 是否存在查看全部的权限:false
INFO 2020-12-15 16:23:40.440 黑名单查询校验不通过

INFO 2020-12-15 16:25:10.922 黑名单权限校验拦截器
INFO 2020-12-15 16:25:10.922 request请求地址url[http://127.0.0.1:8111/phoneBlack/getPhoneBlackList]
INFO 2020-12-15 16:25:10.929 是否存在查看全部的权限:false
INFO 2020-12-15 16:25:10.929 黑名单权限通过

INFO 2020-12-15 16:27:20.964 黑名单权限校验拦截器
INFO 2020-12-15 16:27:20.964 request请求地址url[http://127.0.0.1:8111/phoneBlack/getPhoneBlackList]
INFO 2020-12-15 16:27:20.971 是否存在查看全部的权限:true
INFO 2020-12-15 16:27:20.972 黑名单权限通过

尾言

所有请求都会走拦截器,但是只会拦截配置的请求路径,一般拦截器做的最普遍的就是全部拦截,放开静态文件和登录也之类的操作。

草色烟光残照里,无言谁会凭阑意