接着上篇文章 https://www.cnblogs.com/mxmbk/p/9569438.html
IP访问限制和黑白名单如何做,需要解决以下几个问题:
1、如何识别正常访问和异常访问?(一段时间同一接口访问次数太多?高峰期和低峰期是否不同?)
2、IP访问异常后拒绝策略是什么?(一段时间访问访问异常接口不能访问?高峰期和低峰期是否不同?)
3、是否不同业务的识别方法和拒绝策略不一样?(有些接口访问频率高,有些访问频率低?)
4、有些业务是否之后IP在白名单中才能访问?(只对第三方提供的接口?)
5、IP访问异常的通知?(请求被识别为异常是否通知到服务维护人员?)
先提出问题,在想解决方案,第一版的简单基于Spring cloud zuul的实现方案如下:
具体实现(基于ZuulFilter的实现):
1 package com.brightcns.wuxi.citizencard.zuulserver.filter; 2 3 import com.alibaba.fastjson.JSONObject; 4 import com.brightcns.wuxi.citizencard.common.feature.exception.SystemException; 5 import com.brightcns.wuxi.citizencard.common.feature.util.IPUtils; 6 import com.brightcns.wuxi.citizencard.common.feature.util.MD5Utils; 7 import com.brightcns.wuxi.citizencard.zuulserver.constants.properties.IPLimitProperty; 8 import com.brightcns.wuxi.citizencard.zuulserver.limit.AbstractIPLimitStrategy; 9 import com.brightcns.wuxi.citizencard.zuulserver.limit.IPLimitFactory; 10 import com.google.common.collect.Lists; 11 import com.netflix.zuul.ZuulFilter; 12 import com.netflix.zuul.context.RequestContext; 13 import lombok.extern.slf4j.Slf4j; 14 import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; 15 import javax.servlet.http.HttpServletRequest; 16 import java.util.List; 17 import static com.brightcns.wuxi.citizencard.order.constants.enums.ZuulErrorCode.IP_LIMIT; 18 19 /** 20 * @author maxianming 21 * @date 2018/8/31 10:25 22 */ 23 @Slf4j 24 public class IPLimitFilter extends ZuulFilter { 25 // 白名单URI 26 private List<String> excludeUrl = Lists.newArrayList("/health","/info"); 27 // 响应类型 28 public final String JSON_TYPE = "application/json;charset=UTF-8"; 29 30 @Override 31 public String filterType() { 32 return FilterConstants.PRE_TYPE; 33 } 34 35 @Override 36 public int filterOrder() { 37 return 0; 38 } 39 40 @Override 41 public boolean shouldFilter() { 42 RequestContext context = RequestContext.getCurrentContext(); 43 HttpServletRequest request = context.getRequest(); 44 String requestUri = request.getRequestURI(); 45 if (excludeUrl.contains(requestUri)) { 46 return false; 47 } 48 return true; 49 } 50 51 @Override 52 public Object run() { 53 RequestContext context = RequestContext.getCurrentContext(); 54 HttpServletRequest request = context.getRequest(); 55 String requestIp = IPUtils.getIpAddress(request); 56 String requestUri = request.getRequestURI(); 57 log.info("网关接受requestIp:[{}], requestUri:[{}]请求", requestIp, requestUri); 58 try { 59 AbstractIPLimitStrategy ipLimitStrategy = IPLimitFactory.getIPLimitStragy(); 60 boolean result = ipLimitStrategy.isIPLimit(requestIp, requestUri); 61 if (result) { 62 log.info("requestIp:{},requestUri:{}访问限制", requestIp, requestUri); 63 context.setSendZuulResponse(false); 64 context.setResponseStatusCode(200); 65 context.setResponseBody(IP_LIMIT.getCode() + ":" + IP_LIMIT.getMsg()); 66 context.getResponse().setContentType(JSON_TYPE); 67 } 68 } catch (Exception e) { 69 log.error("IP限制异常", e); 70 } 71 return null; 72 } 73 74 75 76 }
1、基于ZuulFilter的简单实现,ZuulFilter的使用可以自行百度,可参考 https://blog.csdn.net/dream_broken/article/details/77197585
2、63-66行代码 主要是Filter不继续执行其他Filter,响应JSON给调用端
3、59行和60行重点主要采用了策略模式(黑天和白天不同策略)涉及敏感信息 只表明思路
具体思路:
- 采用redis incby 和 expire进行访问次数的统计和有效期的设置
- redis key的生成规则: PREFIX:IP:MD5(uri)
- 黑名单暂时配置文件中配置