当前位置: 代码网 > it编程>编程语言>Java > SpringBoot集成ip2region实现ip白名单的代码示例

SpringBoot集成ip2region实现ip白名单的代码示例

2024年08月11日 Java 我要评论
1.什么是ip2region?ip2region v2.0 - 是一个离线ip地址定位库和ip定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的 xdb 数据生成和查询客户端实现。ip

1.什么是ip2region?

ip2region v2.0 - 是一个离线ip地址定位库和ip定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的 xdb 数据生成和查询客户端实现。

ip2region 特性

1、标准化的数据格式

每个 ip 数据段的 region 信息都固定了格式:国家|区域|省份|城市|isp,只有中国的数据绝大部分精确到了城市,其他国家部分数据只能定位到国家,后前的选项全部是0。

2、数据去重和压缩

xdb 格式生成程序会自动去重和压缩部分数据,默认的全部 ip 数据,生成的 ip2region.xdb 数据库是 11mib,随着数据的详细度增加数据库的大小也慢慢增大。

3、极速查询响应

即使是完全基于 xdb 文件的查询,单次查询响应时间在十微秒级别,可通过如下两种方式开启内存加速查询:

  • vindex 索引缓存 :使用固定的 512kib 的内存空间缓存 vector index 数据,减少一次 io 磁盘操作,保持平均查询效率稳定在10-20微秒之间。
  • xdb 整个文件缓存:将整个 xdb 文件全部加载到内存,内存占用等同于 xdb 文件大小,无磁盘 io 操作,保持微秒级别的查询效率。

4、ip 数据管理框架

v2.0 格式的 xdb 支持亿级别的 ip 数据段行数,region 信息也可以完全自定义,例如:你可以在 region 中追加特定业务需求的数据,例如:gps信息/国际统一地域信息编码/邮编等。也就是你完全可以使用 ip2region 来管理你自己的 ip 定位数据。

2.代码工程

实验目标

根据来源ip 判断属于那个国家,然后做过滤

pom.xml

<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/pom/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
         xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactid>springboot-demo</artifactid>
        <groupid>com.et</groupid>
        <version>1.0-snapshot</version>
    </parent>
    <modelversion>4.0.0</modelversion>

    <artifactid>ipfilter</artifactid>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-web</artifactid>
        </dependency>

        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-autoconfigure</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-test</artifactid>
            <scope>test</scope>
        </dependency>
        <!--    ip lib-->
        <dependency>
            <groupid>org.lionsoul</groupid>
            <artifactid>ip2region</artifactid>
            <version>2.6.4</version>
        </dependency>
        <dependency>
            <groupid>org.projectlombok</groupid>
            <artifactid>lombok</artifactid>
        </dependency>
        <dependency>
            <groupid>com.alibaba.fastjson2</groupid>
            <artifactid>fastjson2</artifactid>
            <version>2.0.40</version>
        </dependency>
    </dependencies>
</project>

controller

package com.et.ipfilter.controller;

import com.et.ipfilter.util.addressutils;
import com.et.ipfilter.util.ipofflineutil;
import com.et.ipfilter.util.iponlineutil;
import lombok.extern.slf4j.slf4j;
import org.springframework.util.stringutils;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;

import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
import java.util.hashmap;
import java.util.map;

@restcontroller
@slf4j
public class helloworldcontroller {
    @requestmapping("/hello")
    public map<string, object> showhelloworld(httpservletrequest httpservletrequest, httpservletresponse httpservletresponse,string ip){

        //fisrt get ip addr by offline file
        //string ip = ipofflineutil.getipaddr(httpservletrequest);
        //analyze address
        string addr = ipofflineutil.getaddr(ip);
        if(stringutils.isempty(addr)) {
            //get addr by online service
            ip = ipofflineutil.getipaddr(httpservletrequest);
            addr= addressutils.getrealaddressbyip(ip);
            log.info("ip >> {},address >> {}", ip, addr);
         // you can filter by country or province
        }
        map<string, object> map = new hashmap<>();
        map.put("msg", "helloworld");
        map.put("ipaddr", addr);
        return map;
    }
}

dto

package com.et.ipfilter.dto;

import lombok.allargsconstructor;
import lombok.data;
import lombok.noargsconstructor;

    @data
    @noargsconstructor
    @allargsconstructor
    public  class countryinfo {
        private string query;
        private string status;
        private string country;
        private string countrycode;
        private string region;
        private string regionname;
        private string city;
        private string zip;
        private string lat;
        private string lon;
        private string timezone;
        private string isp;
        private string org;
        private string as;

}

util

离线查询ip来源,

下载离线ip定位库

离线数据库在项目的data文件夹下,名称为ip2region.db,其他2个文件是用于生成离线库的,可不用下载。

https://github.com/lionsoul2014/ip2region/tree/master/data/ip2region.xdb

下载到离线数据库后,我们需要读取这个数据库,我们可以放在项目的resources目录

package com.et.ipfilter.util;

import lombok.extern.slf4j.slf4j;
import org.lionsoul.ip2region.xdb.searcher;
import org.springframework.util.stringutils;

import javax.servlet.http.httpservletrequest;

/**
 * ip query
 */
@slf4j
public class ipofflineutil {

    private static final string unknown = "unknown";

    protected ipofflineutil() {
    }


    public static string getipaddr(httpservletrequest request) {
        string ip = request.getheader("x-forwarded-for");

        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getheader("proxy-client-ip");
        }
        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getheader("wl-proxy-client-ip");
        }
        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getheader("http_x_forwarded_for");
        }
        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getheader("http_x_forwarded");
        }
        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getheader("http_x_cluster_client_ip");
        }
        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getheader("http_client_ip");
        }
        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getheader("http_forwarded_for");
        }
        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getheader("http_forwarded");
        }
        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getheader("http_via");
        }
        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getheader("remote_addr");
        }
        if (!stringutils.haslength(ip) || unknown.equalsignorecase(ip)) {
            ip = request.getremoteaddr();
        }


        int index = ip.indexof(",");
        if (index != -1) {
            ip = ip.substring(0, index);
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    public static string getaddr(string ip) {
        string dbpath = "d:\\ideaprojects\\etframework\\ipfilter\\src\\main\\resources\\ip2region\\ip2region.xdb";
        // 1、from dbpath load all xdb to memory。
        byte[] cbuff;
        try {
            cbuff = searcher.loadcontentfromfile(dbpath);
        } catch (exception e) {
            log.info("failed to load content from `%s`: %s\n", dbpath, e);
            return null;
        }

        // 2、usr cbuff create a query object base on memory。
        searcher searcher;
        try {
            searcher = searcher.newwithbuffer(cbuff);
        } catch (exception e) {
            log.info("failed to create content cached searcher: %s\n", e);
            return null;
        }
        // 3、query
        try {
            string region = searcher.search(ip);
            return region;
        } catch (exception e) {
            log.info("failed to search(%s): %s\n", ip, e);
        }
        return null;
    }
}

在线查询访问ip

package com.et.ipfilter.util;

import com.et.ipfilter.dto.countryinfo;
import org.springframework.http.responseentity;
import org.springframework.web.client.resttemplate;

import javax.annotation.postconstruct;

/**
 * @author liuhaihua
 * @version 1.0
 * @classname iponlineutil
 * @description todo
 * @date 2024/08/09/ 9:58
 */

public class iponlineutil {
    private static resttemplate resttemplate;

    private final resttemplate template;

    public static final string ip_api_url = "http://ip-api.com/json/";

    public iponlineutil(resttemplate resttemplate) {
        this.template = resttemplate;
    }

    /**
     * init resttemplate
     */
    @postconstruct
    public void init() {
        setresttemplate(this.template);
    }

    /**
     * init resttemplate
     */
    private static void setresttemplate(resttemplate template) {
        resttemplate = template;
    }

    /**
     * get country by ip
     *
     * @param ip
     * @return
     */
    public static countryinfo getcountrybyiponline(string ip) {
        responseentity<countryinfo> entity = resttemplate.getforentity(
                ip_api_url + ip + "?lang=zh-cn",
                countryinfo.class
        );
        return entity.getbody();


    }
}

ip 查询工具类

package com.et.ipfilter.util;

import org.lionsoul.ip2region.xdb.searcher;
import java.io.ioexception;
 
public class searcheriputils {
    public static string  getcacheposition(string ip) {
        return searcheriputils.getcacheposition("src/main/resources/ip2region/ip2region.xdb", ip, true);
    }
 
    public static string  getposition(string dbpath,string ip,boolean format) {
        // 1、create searcher object
        searcher searcher = null;
        try {
            searcher = searcher.newwithfileonly(dbpath);
        } catch (ioexception e) {
            throw new runtimeexception(e);
        }
 
        // 2、query
        try {
            string region = searcher.search(ip);
            if (format){
                return region;
            }
            string[] split = region.split("\\|");
            string s = split[0] + split[2] + split[3];
            return s;
        } catch (exception e) {
            throw new runtimeexception(e);
        }

    }
 
    /**
     * @description :
     * @author : mabo
    */
    public static string getindexcacheposition(string dbpath, string ip, boolean format) {
        searcher searcher = null;
        byte[] vindex;
        try {
            vindex = searcher.loadvectorindexfromfile(dbpath);
        } catch (exception e) {
            throw new runtimeexception(e);
        }
        try {
            searcher = searcher.newwithvectorindex(dbpath, vindex);
        } catch (exception e) {
            throw new runtimeexception(e);
        }
        try {
            string region = searcher.search(ip);
            if (format){
                return region;
            }
            string[] split = region.split("\\|");
            string s = split[0] + split[2] + split[3];
            return s;
        } catch (exception e) {
            throw new runtimeexception(e);
        }
    }
 
    /**
     * @description :
     * @author : mabo
     */
    public static string  getcacheposition(string dbpath,string ip,boolean format) {
        byte[] cbuff;
        try {
            cbuff = searcher.loadcontentfromfile(dbpath);
        } catch (exception e) {
            throw new runtimeexception(e);
        }
 
        searcher searcher;
        try {
            searcher = searcher.newwithbuffer(cbuff);
        } catch (exception e) {
            throw new runtimeexception(e);
        }
        try {
            string region = searcher.search(ip);
            if (format){
                return region;
            }
            string[] split = region.split("\\|");
            string s = split[0] + split[2] + split[3];
            return s;
        } catch (exception e) {
            throw new runtimeexception(e);
        }
 
    }
}


package com.et.ipfilter.util;

import com.alibaba.fastjson2.jsonobject;
import lombok.extern.slf4j.slf4j;
import org.springframework.util.stringutils;

import java.io.bufferedreader;
import java.io.ioexception;
import java.io.inputstreamreader;
import java.net.connectexception;
import java.net.sockettimeoutexception;
import java.net.url;
import java.net.urlconnection;

@slf4j
public class addressutils {

    public static final string ip_url = "http://whois.pconline.com.cn/ipjson.jsp";
 
    public static final string unknown = "xx xx";
 
    public static string getrealaddressbyip(string ip) {
        string address = unknown;
         //if ip is inner ip,return
        if (internalip(ip)) {
            return "inner ip";
        }
        if (true) {
            try {
                string rspstr = sendget(ip_url, "ip=" + ip + "&json=true" ,"gbk");
                if (stringutils.isempty(rspstr)) {
                    log.error("get addr exception {}" , ip);
                    return unknown;
                }
                jsonobject obj = jsonobject.parseobject(rspstr);
                string region = obj.getstring("pro");
                string city = obj.getstring("city");
                return string.format("%s %s" , region, city);
            } catch (exception e) {
                log.error("get addr exception {}" , ip);
            }
        }
        return address;
    }
 
    public static string sendget(string url, string param, string contenttype) {
        stringbuilder result = new stringbuilder();
        bufferedreader in = null;
        try {
            string urlnamestring = url + "?" + param;
            log.info("sendget - {}" , urlnamestring);
            url realurl = new url(urlnamestring);
            urlconnection connection = realurl.openconnection();
            connection.setrequestproperty("accept" , "*/*");
            connection.setrequestproperty("connection" , "keep-alive");
            connection.setrequestproperty("user-agent" , "mozilla/4.0 (compatible; msie 6.0; windows nt 5.1;sv1)");
            connection.connect();
            in = new bufferedreader(new inputstreamreader(connection.getinputstream(), contenttype));
            string line;
            while ((line = in.readline()) != null) {
                result.append(line);
            }
            log.info("recv - {}" , result);
        } catch (connectexception e) {
            log.error("invoke httputils.sendget connectexception, url=" + url + ",param=" + param, e);
        } catch (sockettimeoutexception e) {
            log.error("invoke httputils.sendget sockettimeoutexception, url=" + url + ",param=" + param, e);
        } catch (ioexception e) {
            log.error("invoke httputils.sendget ioexception, url=" + url + ",param=" + param, e);
        } catch (exception e) {
            log.error("invoke httpsutil.sendget exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (exception ex) {
                log.error("invoke in.close exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.tostring();
    }
 
 
    /**
     * check the ip is inner?
     *
     * @param ip
     * @return
     */
    public static boolean internalip(string ip) {
        byte[] addr = texttonumericformatv4(ip);
        return internalip(addr) || "127.0.0.1".equals(ip);
    }
 
    /**
     * check the ip is inner?
     *
     * @param addr
     * @return
     */
    private static boolean internalip(byte[] addr) {
        if (null==addr|| addr.length < 2) {
            return true;
        }
        final byte b0 = addr[0];
        final byte b1 = addr[1];
        // 10.x.x.x/8
        final byte section_1 = 0x0a;
        // 172.16.x.x/12
        final byte section_2 = (byte) 0xac;
        final byte section_3 = (byte) 0x10;
        final byte section_4 = (byte) 0x1f;
        // 192.168.x.x/16
        final byte section_5 = (byte) 0xc0;
        final byte section_6 = (byte) 0xa8;
        switch (b0) {
            case section_1:
                return true;
            case section_2:
                return (b1 >= section_3 && b1 <= section_4);
            case section_5:
                return (b1 == section_6);
            default:
                return false;
        }
    }
 
    /**
     * change ipv4 to byte
     *
     * @param text
     * @return byte
     */
    private static byte[] texttonumericformatv4(string text) {
        if (text.length() == 0) {
            return new byte[0];
        }
 
        byte[] bytes = new byte[4];
        string[] elements = text.split("\\.", -1);
        try {
            long l;
            int i;
            switch (elements.length) {
                case 1:
                    l = long.parselong(elements[0]);
                    if ((l < 0l) || (l > 4294967295l)) {
                        return new byte[0];
                    }
                    bytes[0] = (byte) (int) (l >> 24 & 0xff);
                    bytes[1] = (byte) (int) ((l & 0xffffff) >> 16 & 0xff);
                    bytes[2] = (byte) (int) ((l & 0xffff) >> 8 & 0xff);
                    bytes[3] = (byte) (int) (l & 0xff);
                    break;
                case 2:
                    l = integer.parseint(elements[0]);
                    if ((l < 0l) || (l > 255l)) {
                        return new byte[0];
                    }
                    bytes[0] = (byte) (int) (l & 0xff);
                    l = integer.parseint(elements[1]);
                    if ((l < 0l) || (l > 16777215l)) {
                        return new byte[0];
                    }
                    bytes[1] = (byte) (int) (l >> 16 & 0xff);
                    bytes[2] = (byte) (int) ((l & 0xffff) >> 8 & 0xff);
                    bytes[3] = (byte) (int) (l & 0xff);
                    break;
                case 3:
                    for (i = 0; i < 2; ++i) {
                        l = integer.parseint(elements[i]);
                        if ((l < 0l) || (l > 255l)) {
                            return new byte[0];
                        }
                        bytes[i] = (byte) (int) (l & 0xff);
                    }
                    l = integer.parseint(elements[2]);
                    if ((l < 0l) || (l > 65535l)) {
                        return new byte[0];
                    }
                    bytes[2] = (byte) (int) (l >> 8 & 0xff);
                    bytes[3] = (byte) (int) (l & 0xff);
                    break;
                case 4:
                    for (i = 0; i < 4; ++i) {
                        l = integer.parseint(elements[i]);
                        if ((l < 0l) || (l > 255l)) {
                            return new byte[0];
                        }
                        bytes[i] = (byte) (int) (l & 0xff);
                    }
                    break;
                default:
                    return new byte[0];
            }
        } catch (numberformatexception e) {
            return new byte[0];
        }
        return bytes;
    }
 
}

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

3.测试

  • 启动 springboot应用
  • 访问http://127.0.0.1:8088/hello?ip=52.220.113.16
  • 可以看到该ip属于新加坡,后续可以根据国家限制访问

以上就是springboot集成ip2region实现ip白名单的代码示例的详细内容,更多关于springboot ip白名单的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com