Jak wyodrębnić adres IP w Spring MVC Controller Odbierz połączenie?

93

Pracuję nad projektem kontrolera Spring MVC, w którym wykonuję wywołanie GET URL z przeglądarki -

Poniżej znajduje się adres URL, za pomocą którego wykonuję połączenie GET z przeglądarki -

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

A poniżej jest kod, w którym połączenie przychodzi po kliknięciu w przeglądarkę -

@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
    }

Stwierdzenie problemu: -

Czy jest jakiś sposób, żebym mógł wyodrębnić adres IP z jakiegoś nagłówka? Czyli chciałbym wiedzieć, z jakiego adresu IP przychodzi połączenie, co oznacza, że ​​ktokolwiek dzwoni powyżej adresu URL, muszę znać jego adres IP. Czy to się da zrobić?

Jan
źródło
Spróbuj użyć Spring AOP i obsłużyć HttpServletRequest. stackoverflow.com/questions/19271807/…
Dilip G

Odpowiedzi:

148

Rozwiązaniem jest

@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
    }

Dodaj HttpServletRequest requestdo definicji metody, a następnie użyj interfejsu API serwletów

Dokumentacja wiosenna, o której mowa w

15.3.2.3 Obsługiwane argumenty metod obsługi i typy zwracane

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
Koitoer
źródło
1
Dzięki Koitoer za pomoc. Jedno szybkie pytanie, załóżmy, że jeśli wywołanie pochodzi z Load Balancer zamiast z określonej maszyny, to również zadziała? Chyba nie ...
john
Nie, nie będzie, ale istnieje pewna konfiguracja w
module równoważenia obciążenia,
Sprawdź, czy moduł równoważenia obciążenia może wysyłać te wartości w nagłówku, więc rozważ użycie metody getHeader z HttpServletRequest.
Koitoer,
Koitoer Działa idealnie !! Ale jest inny sposób niż HttpServletRequest.
Harshal Patil,
1
To jest przestarzałe.
Gewure
112

Jestem spóźniony, ale to może pomóc komuś, kto szuka odpowiedzi. Zwykle servletRequest.getRemoteAddr()działa.

W wielu przypadkach użytkownicy aplikacji mogą uzyskiwać dostęp do serwera WWW za pośrednictwem serwera proxy lub może aplikacja znajduje się za modułem równoważenia obciążenia.

Dlatego w takim przypadku należy uzyskać dostęp do nagłówka http X-Forwarded-For, aby uzyskać adres IP użytkownika.

na przykład String ipAddress = request.getHeader("X-FORWARDED-FOR");

Mam nadzieję że to pomoże.

sunitkatkar
źródło
11
Zauważ, że X-Forwarded-Forjest to zwykle lista adresów IP oddzielonych przecinkami, przy czym każdy serwer proxy w łańcuchu dodaje do listy adres zdalny, który widzi. Zatem dobra implementacja generalnie miałaby listę zaufanych serwerów proxy i „pomijała” te ips podczas czytania tego nagłówka od prawej do lewej.
Raman
jak uzyskać adres ip jako 111.111.111.111/X
Muneeb Mirza
26

Używam do tego takiej metody

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();
    }
}
panser
źródło
1
gdzie go używać?
Maifee Ul Asad
12

Możesz uzyskać adres IP statycznie z RequestContextHolderponiższego:

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

String ip = request.getRemoteAddr();
Radouane ROUFID
źródło
4

Umieść tę metodę w swoim BaseController:

@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;
}
BaiJiFeiLong
źródło
4

Zobacz poniżej. Ten kod działa z rozruchem sprężynowym i rozruchem sprężynowym + 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());

:)

Vagner Nogueira
źródło
3

Poniżej znajduje się sposób wiosenny, z autowiredfasolą żądania w @Controllerklasie:

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());
Leon
źródło
1
Może to powodować problemy z jednoczesnym używaniem kontrolera w wielu wątkach. Do @Controllerinstancji należy wstrzykiwać tylko singletony za pomocą @Autowired. W przeciwnym razie należy użyć @Scope(BeanDefinition.SCOPE_PROTOTYPE)klasy kontrolera, aby upewnić się, że nowe wystąpienie kontrolera jest tworzone z każdym żądaniem. Jest to mniej wydajne, ale jest obejściem, jeśli musisz wstrzyknąć coś jako właściwość do klasy kontrolera.
Andy
1

W moim przypadku używałem Nginx przed moją aplikacją z następującą konfiguracją:

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';
}

więc w mojej aplikacji otrzymuję prawdziwy adres IP użytkownika:

String clientIP = request.getHeader("X-Real-IP");
BaDr Amer
źródło
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();
    }

Łączę powyższy kod, aby ten kod działał w większości przypadków. Przekaż HttpServletRequest requestotrzymane z interfejsu API do metody

Kyo Huu
źródło