主要利用Zuul的过滤器来实现该功能,其过滤器还可以用来实现统一的签名和验签服务以及其他任何你需要的服务,本例实现简单的IP过滤功能
新建IPFilter类,继承ZuulFilter,实现其方法
@Slf4j
@Component
public class IPFilter extends ZuulFilter {
@Override
public String filterType() {
// 过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。这里定义为pre,代表会在请求被路由之前执行。另外还有“route”、“post”、"error”等类型
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
// int值来定义过滤器的执行顺序,数值越小优先级越高
return Integer.MIN_VALUE + 1;
}
@Override
public boolean shouldFilter() {
// 判断该过滤器是否需要被执行。这里我们直接返回true,因此该过滤器对所有请求都会生效,实际运用中我们可以利用该函数来指定过滤器的有效范围
return true;
}
@Override
public Object run() {
// 过滤器的具体逻辑。IP校验不通过时我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求,不对其进行路由
// 然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码,通过ctx.setResponseBody(body)返回body内容
RequestContext ctx= RequestContext.getCurrentContext();
HttpServletRequest req=ctx.getRequest();
String ipAddr=this.getIpAddr(req);
log.info("请求IP地址为:[{}]",ipAddr);
//配置本地IP白名单,生产环境可放入数据库或者redis中
List<String> ips=new ArrayList<String>();
ips.add("127.0.0.1");
if(!ips.contains(ipAddr)){
log.info("IP地址校验不通过!!!");
ctx.setResponseStatusCode(401);
ctx.setSendZuulResponse(false);
ctx.setResponseBody("IpAddr is forbidden!");
}
log.info("IP校验通过");
return null;
}
/**
* 获取Ip地址
* @param request
* @return
*/
public String getIpAddr(HttpServletRequest request){
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
电光石火-穿越时空