Wie extrahiere ich die IP-Adresse in Spring MVC Controller, um einen Anruf zu erhalten?

92

Ich arbeite an einem Spring MVC Controller-Projekt, in dem ich einen GET URL-Aufruf vom Browser aus mache.

Unten ist die URL, über die ich einen GET-Anruf vom Browser aus tätige -

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

Und unten ist der Code, in dem der Anruf nach dem Drücken auf den Browser kommt -

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

Problemstellung:-

Gibt es eine Möglichkeit, die IP-Adresse aus einem Header zu extrahieren? Das heißt, ich möchte wissen, von welcher IP-Adresse der Anruf kommt, dh wer über der URL anruft, muss seine IP-Adresse kennen. Ist das möglich?

John
quelle
Versuchen Sie es mit Spring AOP und behandeln Sie HttpServletRequest. stackoverflow.com/questions/19271807/…
Dilip G

Antworten:

147

Die Lösung ist

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

Fügen Sie HttpServletRequest requestIhrer Methodendefinition hinzu und verwenden Sie dann die Servlet-API

Frühlingsdokumentation hier gesagt in

15.3.2.3 Unterstützte Argumente und Rückgabetypen für Handlermethoden

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
quelle
1
Danke Koitoer für die Hilfe. Eine kurze Frage: Angenommen, der Anruf kommt von Load Balancer anstelle eines bestimmten Computers. Dann funktioniert dies auch. Ich denke nicht ..
John
Nein, wird es nicht, aber es gibt einige Konfigurationen im Loadbalancer, die die IP senden können, da sie nicht vorhanden sind. Wahrscheinlich ist dies Ihr Fall
Koitoer
Überprüfen Sie, ob Load Balancer diese Werte wahrscheinlich in einem Header senden kann. Verwenden Sie daher die Methode getHeader von HttpServletRequest.
Koitoer
Koitoer Es funktioniert perfekt !! Es gibt jedoch einen anderen Weg als HttpServletRequest.
Harshal Patil
1
Dies ist veraltet.
Gewure
112

Ich bin spät dran, aber das könnte jemandem helfen, nach der Antwort zu suchen. Funktioniert normalerweise servletRequest.getRemoteAddr().

In vielen Fällen greifen Benutzer Ihrer Anwendung möglicherweise über einen Proxyserver auf Ihren Webserver zu, oder Ihre Anwendung befindet sich hinter einem Load Balancer.

In einem solchen Fall sollten Sie auf den X-Forwarded-For http-Header zugreifen , um die IP-Adresse des Benutzers abzurufen.

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

Hoffe das hilft.

sunitkatkar
quelle
11
Beachten Sie, dass X-Forwarded-Fores sich im Allgemeinen um eine durch Kommas getrennte Liste von IPs handelt, wobei jeder Proxy in der Kette die entfernte Adresse, die er sieht, zur Liste hinzufügt. Eine gute Implementierung würde also im Allgemeinen eine Liste vertrauenswürdiger Proxys haben und diese IPs "überspringen", wenn dieser Header von rechts nach links gelesen wird.
Raman
Wie bekomme ich die IP-Adresse als 111.111.111.111/X
Muneeb Mirza
25

Ich benutze eine solche Methode, um dies zu tun

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
quelle
1
wo benutze ich es
Maifee Ul Asad
12

Sie können die IP-Adresse statisch RequestContextHolderwie folgt abrufen :

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

String ip = request.getRemoteAddr();
Radouane ROUFID
quelle
4

Fügen Sie diese Methode in Ihren BaseController ein:

@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
quelle
4

Siehe unten. Dieser Code funktioniert mit Spring-Boot und 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());

:) :)

Vagner Nogueira
quelle
3

Unten ist der Frühlingsweg mit autowiredAnforderungsbohne in der @ControllerKlasse:

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());
Leon
quelle
1
Dies kann zu Problemen bei der gleichzeitigen Verwendung des Controllers über mehrere Threads hinweg führen. Es sollten nur Singletons in @ControllerInstanzen mit injiziert werden @Autowired. Andernfalls müssen Sie @Scope(BeanDefinition.SCOPE_PROTOTYPE)die Controller-Klasse verwenden, um sicherzustellen, dass bei jeder Anforderung eine neue Instanz des Controllers erstellt wird. Dies ist weniger effizient, stellt jedoch eine Problemumgehung dar, wenn Sie der Controller-Klasse etwas als Eigenschaft hinzufügen müssen.
Andy
1

In meinem Fall habe ich Nginx vor meiner Anwendung mit der folgenden Konfiguration verwendet:

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

So bekomme ich in meiner Anwendung die echte Benutzer-IP wie folgt:

String clientIP = request.getHeader("X-Real-IP");
BaDr Amer
quelle
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();
    }

Ich kombiniere den obigen Code mit dieser Code-Arbeit für die meisten Fälle. Übergeben HttpServletRequest requestSie das, was Sie von der API erhalten, an die Methode

Kyo Huu
quelle