Bagaimana cara mengekstrak Alamat IP di Spring MVC Controller mendapatkan panggilan?


93

Saya sedang mengerjakan proyek pengontrol MVC Spring di mana saya membuat panggilan GET URL dari browser -

Di bawah ini adalah url yang saya gunakan untuk melakukan panggilan GET dari browser -

http://127.0.0.1:8080/testweb/processing?workflow=test&conf=20140324&dc=all

Dan di bawah ini adalah kode di mana panggilan muncul setelah masuk ke browser -

@RequestMapping(value = "processing", method = RequestMethod.GET)
public @ResponseBody ProcessResponse processData(@RequestParam("workflow") final String workflow,
    @RequestParam("conf") final String value, @RequestParam("dc") final String dc) {

        System.out.println(workflow);
        System.out.println(value);
        System.out.println(dc);

        // some other code
    }

Pernyataan masalah:-

Sekarang adakah cara, saya dapat mengekstrak Alamat IP dari beberapa header? Artinya saya ingin tahu dari alamat IP mana, panggilan datang, artinya siapa pun yang menelepon di atas URL, saya perlu tahu alamat IP mereka. Apakah ini mungkin untuk dilakukan?


Coba gunakan Spring AOP dan tangani HttpServletRequest. stackoverflow.com/questions/19271807/…
Dilip G

Jawaban:


149

Solusinya adalah

@RequestMapping(value = "processing", method = RequestMethod.GET)
public @ResponseBody ProcessResponse processData(@RequestParam("workflow") final String workflow,
    @RequestParam("conf") final String value, @RequestParam("dc") final String dc, HttpServletRequest request) {

        System.out.println(workflow);
        System.out.println(value);
        System.out.println(dc);
        System.out.println(request.getRemoteAddr());
        // some other code
    }

Tambahkan HttpServletRequest requestke definisi metode Anda dan kemudian gunakan Servlet API

Dokumentasi Musim Semi di sini tertulis

15.3.2.3 Argumen metode penanganan yang didukung dan tipe kembalian

Handler methods that are annotated with @RequestMapping can have very flexible signatures.
Most of them can be used in arbitrary order (see below for more details).

Request or response objects (Servlet API). Choose any specific request or response type,
for example ServletRequest or HttpServletRequest

1
Terima kasih Koitoer atas bantuannya. Satu pertanyaan singkat, misalkan jika panggilan tersebut berasal dari Load Balancer dan bukan dari mesin tertentu, maka ini akan berfungsi juga? Saya kira tidak ..
john

Tidak, tetapi ada beberapa konfigurasi di loadbalancer yang dapat mengirim IP karena tidak ada, mungkin ini kasus Anda
Koitoer

Periksa apakah penyeimbang beban dapat mengirim nilai-nilai tersebut dalam sebuah header, jadi pertimbangkan untuk menggunakan metode getHeader dari HttpServletRequest.
Koitoer

Koitoer Bekerja dengan sempurna !! Tetapi ada cara lain selain HttpServletRequest.
Harshal Patil

1
Ini sudah usang.
Gewure

112

Saya terlambat di sini, tetapi ini mungkin membantu seseorang mencari jawabannya. Biasanya servletRequest.getRemoteAddr()bekerja.

Dalam banyak kasus, pengguna aplikasi Anda mungkin mengakses server web Anda melalui server proxy atau mungkin aplikasi Anda berada di belakang penyeimbang beban.

Jadi Anda harus mengakses header http X-Forwarded-For dalam kasus seperti itu untuk mendapatkan alamat IP pengguna.

misalnya String ipAddress = request.getHeader("X-FORWARDED-FOR");

Semoga ini membantu.


11
Perhatikan bahwa X-Forwarded-Forbiasanya daftar ips dipisahkan dengan koma, dengan setiap proxy dalam rangkaian menambahkan alamat jarak jauh yang dilihatnya ke daftar. Jadi, implementasi yang baik biasanya memiliki daftar proxy tepercaya dan "lewati" ip tersebut saat membaca header ini dari kanan ke kiri.
Raman

cara mendapatkan alamat ip sebagai 111.111.111.111/X
Muneeb Mirza

26

Saya menggunakan metode seperti itu untuk melakukan ini

public class HttpReqRespUtils {

    private static final String[] IP_HEADER_CANDIDATES = {
        "X-Forwarded-For",
        "Proxy-Client-IP",
        "WL-Proxy-Client-IP",
        "HTTP_X_FORWARDED_FOR",
        "HTTP_X_FORWARDED",
        "HTTP_X_CLUSTER_CLIENT_IP",
        "HTTP_CLIENT_IP",
        "HTTP_FORWARDED_FOR",
        "HTTP_FORWARDED",
        "HTTP_VIA",
        "REMOTE_ADDR"
    };

    public static String getClientIpAddressIfServletRequestExist() {

        if (RequestContextHolder.getRequestAttributes() == null) {
            return "0.0.0.0";
        }

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        for (String header: IP_HEADER_CANDIDATES) {
            String ipList = request.getHeader(header);
            if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) {
                String ip = ipList.split(",")[0];
                return ip;
            }
        }

        return request.getRemoteAddr();
    }
}

1
dimana saya menggunakannya?
Maifee Ul Asad

12

Anda bisa mendapatkan alamat IP secara statis dari RequestContextHolderseperti di bawah ini:

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
        .getRequest();

String ip = request.getRemoteAddr();

4

Letakkan metode ini di BaseController Anda:

@SuppressWarnings("ConstantConditions")
protected String fetchClientIpAddr() {
    HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.getRequestAttributes())).getRequest();
    String ip = Optional.ofNullable(request.getHeader("X-FORWARDED-FOR")).orElse(request.getRemoteAddr());
    if (ip.equals("0:0:0:0:0:0:0:1")) ip = "127.0.0.1";
    Assert.isTrue(ip.chars().filter($ -> $ == '.').count() == 3, "Illegal IP: " + ip);
    return ip;
}

4

Lihat di bawah. Kode ini bekerja dengan spring-boot dan spring-boot + apache CXF / SOAP.

    // in your class RequestUtil
    private static final String[] IP_HEADER_NAMES = { 
                                                        "X-Forwarded-For",
                                                        "Proxy-Client-IP",
                                                        "WL-Proxy-Client-IP",
                                                        "HTTP_X_FORWARDED_FOR",
                                                        "HTTP_X_FORWARDED",
                                                        "HTTP_X_CLUSTER_CLIENT_IP",
                                                        "HTTP_CLIENT_IP",
                                                        "HTTP_FORWARDED_FOR",
                                                        "HTTP_FORWARDED",
                                                        "HTTP_VIA",
                                                        "REMOTE_ADDR"
                                                    };

    public static String getRemoteIP(RequestAttributes requestAttributes)
    {
        if (requestAttributes == null)
        {
            return "0.0.0.0";
        }
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        String ip = Arrays.asList(IP_HEADER_NAMES)
            .stream()
            .map(request::getHeader)
            .filter(h -> h != null && h.length() != 0 && !"unknown".equalsIgnoreCase(h))
            .map(h -> h.split(",")[0])
            .reduce("", (h1, h2) -> h1 + ":" + h2);
        return ip + request.getRemoteAddr();
    }

    //... in service class:
    String remoteAddress = RequestUtil.getRemoteIP(RequestContextHolder.currentRequestAttributes());

:)


3

Di bawah ini adalah cara Spring, dengan autowiredrequest bean di @Controllerkelas:

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());

1
Hal ini dapat menyebabkan masalah dengan penggunaan pengontrol secara bersamaan di beberapa utas. Hanya lajang yang harus disuntikkan ke dalam @Controllercontoh menggunakan @Autowired. Jika tidak, Anda harus menggunakan @Scope(BeanDefinition.SCOPE_PROTOTYPE)kelas pengontrol untuk memastikan bahwa instance baru pengontrol dibuat dengan setiap permintaan. Ini kurang efisien, tetapi merupakan solusi jika Anda harus memasukkan sesuatu sebagai properti ke kelas kontroler.
Andy

1

Dalam kasus saya, saya menggunakan Nginx di depan aplikasi saya dengan konfigurasi berikut:

location / {
     proxy_pass        http://localhost:8080/;
     proxy_set_header  X-Real-IP $remote_addr;
     proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header  Host $http_host;
     add_header Content-Security-Policy 'upgrade-insecure-requests';
}

jadi dalam aplikasi saya, saya mendapatkan ip pengguna yang sebenarnya seperti:

String clientIP = request.getHeader("X-Real-IP");

0
private static final String[] IP_HEADER_CANDIDATES = {
            "X-Forwarded-For",
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_X_FORWARDED_FOR",
            "HTTP_X_FORWARDED",
            "HTTP_X_CLUSTER_CLIENT_IP",
            "HTTP_CLIENT_IP",
            "HTTP_FORWARDED_FOR",
            "HTTP_FORWARDED",
            "HTTP_VIA",
            "REMOTE_ADDR"
    };

    public static String getIPFromRequest(HttpServletRequest request) {
        String ip = null;
        if (request == null) {
            if (RequestContextHolder.getRequestAttributes() == null) {
                return null;
            }
            request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        }

        try {
            ip = InetAddress.getLocalHost().getHostAddress();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (!StringUtils.isEmpty(ip))
            return ip;

        for (String header : IP_HEADER_CANDIDATES) {
            String ipList = request.getHeader(header);
            if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) {
                return ipList.split(",")[0];
            }
        }

        return request.getRemoteAddr();
    }

Saya menggabungkan kode di atas ke kode ini berfungsi untuk banyak kasus. Teruskan yang HttpServletRequest requestAnda dapatkan dari api ke metode

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.