avatar

目录
spring拦截器+hconfig实现百名单控制

白名单介绍

创建元注解

创建一个元注解,标注此元注解的方法才需要进行判断


Code
1
2
3
4
5
6
7
8
9
10
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthorityCheck {
/**
* 接口需要配置公共ip白名单之外的iP时使用
* @return hconfig中的key
*/
public String key() default "";
}

Controller方法标注注解

对需要进行判断的方法加上注解
如果需要为接口单独配置白名单,在注解中加上key,key是hconfig白名单配置中的key
如果不需要单独配置白名单,则@AuthorityCheck,走公共的白名单


Code
1
2
3
4
5
6
@RequestMapping(value = "/mmpInfos.json")
@AuthorityCheck(key = "mmpInfos.ip.white.list")
@ResponseBody
public DappJsonResult queryMaintenanceModeAndPriceInfos() {
return new JsonResult<>(data);
}

拦截器实现

HandlerInterceptorAdapter是一个适配类,也可以直接继承HandlerInterceptor


Code
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
@Component
public class AuthorityInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(AuthorityInterceptor.class);

@Resource
private IPWhiteListService ipWhiteList;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

if (!(handler instanceof HandlerMethod)) {
return true;
}

HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
if (!method.isAnnotationPresent(AuthorityCheck.class)) {
return true;
}

if (!ipWhiteList.isEnabled()) {
logger.debug("白名单禁用");
return true;
}

AuthorityCheck authorityCheck = method.getAnnotation(AuthorityCheck.class);
String realIp = IpUtil.getUserIPString(request);
logger.debug("real ip is: {}", realIp);
return ipWhiteList.isAllowedIp(realIp,authorityCheck.key());
}
}
Code
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
89
90
91
92
93
94
95
@Component
public class IPWhiteListService {

private static final Logger logger = LoggerFactory.getLogger(IPWhiteListService.class);

private static final String COMMON_IP_WHITE_LIST = "common.ip.white.list";

@HConfig("dapp_ip_white_conf.properties")
private Map ipWhiteMap;

public boolean isEnabled() {
String isEnable = getString("ip.white.switch","true");
return "true".equals(isEnable);
}

/**
* 访问ip只要在特定白名单 or 公共单个白名单 or 公共ip段中 则允许访问
* @param realIp
* @param key 接口特定ip白名单hconfig中key
* @return
*/
public boolean isAllowedIp(String realIp,String key) {

if(StringUtils.isNotBlank(key)) {//接口有定制的ip白名单
String unusualIpWhiteList = getString(key,"");
if(unusualIpWhiteList.contains(realIp)) {
return true;
}
}

//所有接口公共的ip白名单
String commonIpWhiteList = getString(COMMON_IP_WHITE_LIST, "127.0.0.1");
return commonIpWhiteList.contains(realIp) || isInIpWhiteRangeList(realIp);
}


//公共ip段白名单校验
public boolean isInIpWhiteRangeList(String ip) {
String rangeIps = getString("common.range.ip.white.list","");
List rangeIpList = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(rangeIps);

if(rangeIpList != null && rangeIpList.size() != 0) {
for (String s : rangeIpList) {
boolean isValid = isInIpWhiteRangeList(s, ip);
if(isValid) {
return true;
}
}
}

return false;
}

/**
* 判断IP是否在指定范围;
* @param ipSection 范围 示例 192.168.1.1-192.168.2.10
* @param ip
* @return
*/

public static boolean isInIpWhiteRangeList(String ipSection, String ip) {
if (StringUtils.isBlank(ipSection) || StringUtils.isBlank(ip) ) {
return false;
}

ipSection = ipSection.trim();
ip = ip.trim();
final String REGX_IP = "((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
final String REGX_IPB = REGX_IP + "\\-" + REGX_IP;
if (!ipSection.matches(REGX_IPB) || !ip.matches(REGX_IP)) {//判断参数是否是ip4格式
return false;
}

int idx = ipSection.indexOf('-');
String[] sips = ipSection.substring(0, idx).split("\\.");
String[] sipe = ipSection.substring(idx + 1).split("\\.");
String[] sipt = ip.split("\\.");
long startIp = 0L, endIp = 0L, realIp = 0L;
for (int i = 0; i < 4; ++i) { //把ip转化成long
startIp = startIp << 8 | Integer.parseInt(sips[i]);
endIp = endIp << 8 | Integer.parseInt(sipe[i]);
realIp = realIp << 8 | Integer.parseInt(sipt[i]);
}
if (startIp > endIp) {
long t = startIp;
startIp = endIp;
endIp = t;
}
return startIp <= realIp && realIp <= endIp;
}

private String getString(String key,String def) {
String value = ipWhiteMap.get(key);
return value == null ? def : value;
}

配置文件

dispatch-servlet.xml文件进行如下修改

Code
1
2
3
4
5





Hconfig白名单配

便于管理hconfig白名单单独拉出来一个文件dapp_ip_white_conf.properties

公共ip段白名单开始结束用 一个横线隔开 “-“
多个ip或者ip段之间用英文逗号 “,”隔开
只要访问ip在 公共ip白名单,公共ip段白名单,接口特定白名单 三者中之一存在则是允许访问的,他们是 or 的关系

Code
1
2
3
4
5
6
7
8
9
10
11
#白名单开关
ip.white.switch=true

#公共的白名单
common.ip.white.list=127.0.0.1

#公共ip段白名单
common.range.ip.white.list=10.89.129.1-10.89.129.255,127.0.0.1-127.0.0.6

#团期接口白名单
mmpInfos.ip.white.list=10.89.129.89
文章作者: 美式不加糖
文章链接: http://yoursite.com/2020/02/04/spring%E6%8B%A6%E6%88%AA%E5%99%A8+hconfig%E5%AE%9E%E7%8E%B0%E7%99%BE%E5%90%8D%E5%8D%95%E6%8E%A7%E5%88%B6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 湖畔小屋
打赏
  • 微信
    微信
  • 支付寶
    支付寶