ソースを参照

优化ip限制

chenweida 6 年 前
コミット
edb19ee41c

+ 4 - 2
common-router-starter/src/main/java/com/yihu/base/router/RouteEndPoint.java

@ -133,7 +133,8 @@ public class RouteEndPoint {
    @ApiOperation(value = "新增路由限制规则", notes = "")
    public String saveRule(
            @ApiParam(name = "id", value = "主键", required = true) @RequestParam(required = true, name = "id") String id,
            @ApiParam(name = "ip", value = "ip地址", required = true) @RequestParam(required = true, name = "ip") String ip,
            @ApiParam(name = "excludeIp", value = "ip地址", required = false) @RequestParam(required = false, name = "excludeIp") String excludeIp,
            @ApiParam(name = "includeIp", value = "ip地址", required = false) @RequestParam(required = false, name = "includeIp") String includeIp,
            @ApiParam(name = "path", value = "限制访问的路径", required = false) @RequestParam(required = false, name = "path") String path,
            @ApiParam(name = "accessCount", value = "次数", required = false) @RequestParam(required = false, name = "accessCount",defaultValue = "0") Integer accessCount,
            @ApiParam(name = "accessUnit", value = "访问的次数限制单位 默认是分钟  1秒 2 分钟 3小时 4天 结合accessCount使用 ", required = false) @RequestParam(required = false, name = "accessUnit",defaultValue = "2") String accessUnit
@ -142,7 +143,8 @@ public class RouteEndPoint {
        ratelimit.setId(id);
        ratelimit.setAccessCount(accessCount);
        ratelimit.setAccessUnit(accessUnit);
        ratelimit.setIp(ip);
        ratelimit.setExcludeIp(excludeIp);
        ratelimit.setIncludeIp(includeIp);
        ratelimit.setPath(path);
        rateLimitStorage.saveRateLimit(ratelimit);
        return "成功";

+ 14 - 5
common-router-starter/src/main/java/com/yihu/base/router/model/Ratelimit.java

@ -11,7 +11,8 @@ import java.time.temporal.ChronoUnit;
 */
public class Ratelimit {
    private String id;//主键
    private String ip;//ip地址 为空默认是全部的ip都可以访问
    private String includeIp;//ip地址 为空默认是全部的ip都可以访问
    private String excludeIp;//ip地址 为空默认是全部的ip都可以访问
    private String path;// 限制访问的路径
    private Integer accessCount = 0;//次数 默认是0 表示没有限制
    private String accessUnit = "2";//访问的次数限制单位 默认是分钟  1秒 2 分钟 3小时 4天 结合accessCount使用
@ -24,12 +25,20 @@ public class Ratelimit {
        this.id = id;
    }
    public String getIp() {
        return ip;
    public String getIncludeIp() {
        return includeIp;
    }
    public void setIp(String ip) {
        this.ip = ip;
    public void setIncludeIp(String includeIp) {
        this.includeIp = includeIp;
    }
    public String getExcludeIp() {
        return excludeIp;
    }
    public void setExcludeIp(String excludeIp) {
        this.excludeIp = excludeIp;
    }
    public String getPath() {

+ 46 - 4
common-router-starter/src/main/java/com/yihu/base/router/ratelimit/IPRateLimiter.java

@ -4,6 +4,7 @@ import com.yihu.base.router.model.Ratelimit;
import com.yihu.base.router.model.Result;
import com.yihu.base.router.model.RuleRoute;
import com.yihu.base.router.ratelimit.storage.IRateLimitStorage;
import com.yihu.base.router.util.IpV4Util;
import com.yihu.base.router.util.NetworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -42,16 +43,17 @@ public class IPRateLimiter implements IRatelimiter {
                    if (!antPathMatcher.match(ratelimit.getPath(), path)) {
                        continue;
                    }
                    //2.判断当前请求的ip是不是可以通过的ip
                    if (requestIP.equals(ratelimit.getIp())||StringUtils.isEmpty(ratelimit.getIp())) {
                    //2.判断IP是否可以通过
                    //如果IP即在 通过列表也在 不通过列表 那也默认不可以通过
                    if (requestIpIsInclude(requestIP, ratelimit.getIncludeIp()) && requestIpIsExclude(requestIP, ratelimit.getExcludeIp())) {
                        //3 判断是否有次数限制
                        //默认是0 表示没有限制
                        if (ratelimit.getAccessCount() == 0) {
                            return new Result();
                        }
                        //如果没有超过次数限制
                        if (!rateLimitStorage.isUpperLimit(ratelimit.getId())) {
                            if (!rateLimitStorage.countDec(ratelimit.getId())) {
                        if (!rateLimitStorage.isUpperLimit(ratelimit.getId(),requestIP)) {
                            if (!rateLimitStorage.countDec(ratelimit.getId(),requestIP)) {
                                return new Result(501, "Request upper limit");
                            }
                            return new Result();
@ -73,6 +75,46 @@ public class IPRateLimiter implements IRatelimiter {
        }
    }
    /**
     * @param requestIP
     * @param includeIp
     * @return
     */
    private boolean requestIpIsInclude(String requestIP, String includeIp) {
        //1 如果includeIp是空默认是通过
        if (StringUtils.isEmpty(includeIp)) {
            return true;
        }
        String[] includeIps=includeIp.split(",");
        //2 如果IP属于这个includeIp 表示通过
        for(String oneIncludeIp:includeIps){
            if(IpV4Util.ipExistsInRange(requestIP,oneIncludeIp)){
                return true;
            }
        }
        return false;
    }
    /**
     * @param requestIP
     * @param ExcludIp
     * @return
     */
    private boolean requestIpIsExclude(String requestIP, String ExcludIp) {
        //1 如果ExcludIp是空默认是通过
        if (StringUtils.isEmpty(ExcludIp)) {
            return true;
        }
        String[] excludeIps=ExcludIp.split(",");
        //2如果IP属于这个ExcludIp 表示不通过
        for(String oneIncludeIp:excludeIps){
            if(IpV4Util.ipExistsInRange(requestIP,oneIncludeIp)){
                return false;
            }
        }
        return true;
    }
    public IRateLimitStorage getRateLimitStorage() {
        return rateLimitStorage;
    }

+ 3 - 3
common-router-starter/src/main/java/com/yihu/base/router/ratelimit/storage/AbstractRateLimitStorage.java

@ -35,17 +35,17 @@ public class AbstractRateLimitStorage implements IRateLimitStorage {
    }
    @Override
    public Boolean countDec(String id) {
    public Boolean countDec(String id,String requestIP) {
        return null;
    }
    @Override
    public Integer getCount(String id) {
    public Integer getCount(String id,String requestIP) {
        return null;
    }
    @Override
    public Boolean isUpperLimit(String id) {
    public Boolean isUpperLimit(String id,String requestIP) {
        return null;
    }

+ 3 - 3
common-router-starter/src/main/java/com/yihu/base/router/ratelimit/storage/IRateLimitStorage.java

@ -47,19 +47,19 @@ public interface IRateLimitStorage {
     * @param id
     * @return
     */
    Boolean countDec(String id);
    Boolean countDec(String id,String requestIP);
    /**
     * 获取次数
     * @param id
     * @return
     */
    Integer getCount(String id);
    Integer getCount(String id,String requestIP);
    /**
     * 判断是否超过次数
     * @param id
     * @return
     */
    Boolean isUpperLimit(String id);
    Boolean isUpperLimit(String id,String requestIP);
}

+ 10 - 9
common-router-starter/src/main/java/com/yihu/base/router/ratelimit/storage/RedisRateLimitStorage.java

@ -30,6 +30,7 @@ public class RedisRateLimitStorage extends AbstractRateLimitStorage {
    private Logger logger = LoggerFactory.getLogger(RedisRateLimitStorage.class);
    private static String redisPre = "router:rateLimit:";
    private static String redisPreCount = "router:rateLimitCount:";
    private static String and = ":";
    private StringRedisTemplate redisTemplate;
@ -101,10 +102,10 @@ public class RedisRateLimitStorage extends AbstractRateLimitStorage {
    }
    @Override
    public Boolean countDec(String id) {
    public Boolean countDec(String id, String requestIP) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            String key = redisPreCount + id;
            String key = redisPreCount + id + and + requestIP;
            if (redisTemplate.hasKey(key)) {
                redisTemplate.watch(key);
                String value = redisTemplate.opsForValue().get(key);
@ -122,7 +123,7 @@ public class RedisRateLimitStorage extends AbstractRateLimitStorage {
                                Date endTime = simpleDateFormat.parse(rateLimitCount.getEndTime());
                                if (new Date().after(endTime)) {
                                    redisTemplate.delete(key);
                                }else{
                                } else {
                                    redisTemplate.expireAt(key, endTime);
                                }
                            } catch (ParseException e) {
@ -160,16 +161,16 @@ public class RedisRateLimitStorage extends AbstractRateLimitStorage {
    }
    @Override
    public Integer getCount(String id) {
    public Integer getCount(String id, String requestIp) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String key = redisPreCount + id;
        String key = redisPreCount + id + and + requestIp;
        String value = redisTemplate.opsForValue().get(key);
        RateLimitCount rateLimitCount = JSON.parseObject(value, RateLimitCount.class);
        try {
            Date endTime = simpleDateFormat.parse(rateLimitCount.getEndTime());
            if (new Date().after(endTime)) {
                redisTemplate.delete(key);
            }else{
            } else {
                redisTemplate.expireAt(key, endTime);
            }
        } catch (ParseException e) {
@ -183,13 +184,13 @@ public class RedisRateLimitStorage extends AbstractRateLimitStorage {
     * @return true 返回时已经达到上限 false表示没有
     */
    @Override
    public Boolean isUpperLimit(String id) {
    public Boolean isUpperLimit(String id, String requestIp) {
        //不存在key的时候默认是可以的
        String key = redisPreCount + id;
        String key = redisPreCount + id + and + requestIp;
        if (!redisTemplate.hasKey(key)) {
            return false;
        }
        return getCount(id) == 0 ? true : false;
        return getCount(id,requestIp) == 0 ? true : false;
    }
    public StringRedisTemplate getRedisTemplate() {

+ 86 - 0
common-router-starter/src/main/java/com/yihu/base/router/util/IpV4Util.java

@ -0,0 +1,86 @@
package com.yihu.base.router.util;
import org.springframework.util.StringUtils;
/**
 * Created by chenweida on 2018/5/31 0031.
 */
public class IpV4Util {
    /**
     *
     *支持单个和网段
     * @param ip
     * @param ipSection   10.10.1.2-11.10.1.2 或者10.10.1.2
     * @return
     */
    public static boolean ipExistsInRange(String ip, String ipSection) {
        ipSection = ipSection.trim();
        ip = ip.trim();
        String[] ipSections = ipSection.split("-");
        if (ipSections.length == 1) {
            return org.apache.commons.lang.StringUtils.equals(ip, ipSections[0]);
        }
        int idx = ipSection.indexOf('-');
        String beginIP = ipSection.substring(0, idx);
        String endIP = ipSection.substring(idx + 1);
        return getIp2long(beginIP) <= getIp2long(ip) && getIp2long(ip) <= getIp2long(endIP);
    }
    private static long getIp2long(String ip) {
        ip = ip.trim();
        String[] ips = ip.split("\\.");
        long ip2long = 0L;
        for (int i = 0; i < 4; ++i) {
            ip2long = ip2long << 8 | Integer.parseInt(ips[i]);
        }
        return ip2long;
    }
    private static long getIp2long2(String ip) {
        ip = ip.trim();
        String[] ips = ip.split("\\.");
        long ip1 = Integer.parseInt(ips[0]);
        long ip2 = Integer.parseInt(ips[1]);
        long ip3 = Integer.parseInt(ips[2]);
        long ip4 = Integer.parseInt(ips[3]);
        long ip2long = 1L * ip1 * 256 * 256 * 256 + ip2 * 256 * 256 + ip3 * 256 + ip4;
        return ip2long;
    }
    public static void main(String[] args) {
        //10.10.10.116 是否属于固定格式的IP段10.10.1.00-10.10.255.255
        String ip = "11.10.1.1";
        String ipSection = "10.10.1.2-11.10.1.2";
        boolean exists = ipExistsInRange(ip, ipSection);
        System.out.println(exists);
    }
}