143

I am working on Spring MVC controller project in which I am making a GET URL call from the browser -

Below is the url by which I am making a GET call from the browser -

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

And below is the code in which the call comes after hitting at the 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
    }

Problem Statement:-

Now is there any way, I can extract IP Address from some header? Meaning I would like to know from which IP Address, call is coming, meaning whoever is calling above URL, I need to know their IP Address. Is this possible to do?

tereško
  • 58,060
  • 25
  • 98
  • 150
john
  • 11,311
  • 40
  • 131
  • 251
  • Try using Spring AOP and handling HttpServletRequest. https://stackoverflow.com/questions/19271807/how-to-inject-httpservletrequest-into-a-spring-aop-request-custom-scenario – Dilip G Nov 21 '19 at 17:54

11 Answers11

187

The solution is

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

Add HttpServletRequest request to your method definition and then use the Servlet API

Spring Documentation here said in

15.3.2.3 Supported handler method arguments and return types

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
  • 18,778
  • 7
  • 63
  • 86
  • 2
    Thanks Koitoer for the help. One quick question, suppose if the call is coming from Load Balancer instead of specific machine then this will work as well? I guess not.. – john Apr 05 '14 at 06:36
  • No it wont, but there are some configuration in the loadbalancer that can send the IP as they does not exist, probably this is your case – Koitoer Apr 05 '14 at 06:37
  • 1
    Check probably load balancer can send those values in a header, so consider using getHeader method of HttpServletRequest. – Koitoer Apr 05 '14 at 06:39
  • Koitoer It works perfectly!! But there is any other way rather than HttpServletRequest. – Harshal Patil Apr 05 '14 at 06:55
  • Also you could use HttpSession but then extract HttpServletRequest lol.. Actually I think the question is there is another way to send the IP information in the request, if the answer is positive there could be another ways to extract, but use the API in the common way I don't even know any other option . If you add the IP in the headers, you can extract them and read the IP info, but this is a customization of the headers, that you can extract with HttpSession object – Koitoer Apr 06 '14 at 08:15
  • 1
    I am getting wrong ip address (0:0:0:0:0:0:0:1) if the request from postman. Do anyone have idea, how to get ip address even if the request from the postman? – Dipesh Gandhi May 02 '15 at 02:31
  • 1
    I'm also getting 0:0:0:0:0:0:0:1 – code Jan 23 '16 at 01:57
  • 1
    This is deprecated. – Gewure May 08 '18 at 00:30
  • @DipeshGandhi were you able to resolve your problem? I am also getting `(0:0:0:0:0:0:0:1)` through postman. Were you able to get pubic IP address? – Eatsam ul haq Oct 10 '22 at 10:24
141

I am late here, but this might help someone looking for the answer. Typically servletRequest.getRemoteAddr() works.

In many cases your application users might be accessing your web server via a proxy server or maybe your application is behind a load balancer.

So you should access the X-Forwarded-For http header in such a case to get the user's IP address.

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

starball
  • 20,030
  • 7
  • 43
  • 238
sunitkatkar
  • 1,958
  • 1
  • 14
  • 12
  • 15
    Note that `X-Forwarded-For` is generally a comma-separated list of ips, with each proxy in the chain adding the remote address it sees to the list. So a good implementation would generally have a list of trusted proxies and "skip" those ips when reading this header from right to left. – Raman May 06 '16 at 04:22
  • how to get ip address as 111.111.111.111/X – Muneeb Mirza Jan 27 '17 at 10:08
  • 8
    Note that e.g. Tomcat has `RemoteIpValve` that parses `X-Forwarded-For` header and sets it on the `HttpServletRequest`, so that `servletRequest.getRemoteAddr()` returns correct end-user IP address. In Spring Boot it can be enabled via `server.tomcat.remote-ip-header=X-Forwarded-For` application property – Gediminas Rimsa Jan 08 '21 at 09:07
  • 1
    Can't `X-FORWARDED-FOR` header be spoofed by the client? Wouldn't it be safer to only assume `X-FORWARDED-FOR` valid if `getRemoteAddr()` belongs to a whitelist of credible proxy service providers? – Klesun Sep 03 '21 at 19:09
  • Spring boot is able to automatically resolve the forwarded IP address for you. See [this question](https://stackoverflow.com/questions/59126518/how-to-cope-with-x-forwarded-headers-in-spring-boot-2-2-0-spring-web-mvc-behin) for details. – icguy Oct 21 '21 at 17:26
57

I use such method to do this

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();
    }
}
Neloop
  • 139
  • 7
panser
  • 1,949
  • 22
  • 16
19

You can get the IP address statically from the RequestContextHolder as below :

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

String ip = request.getRemoteAddr();
Radouane ROUFID
  • 10,595
  • 9
  • 42
  • 80
8

In my case, I was using Nginx in front of my application with the following configuration:

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 in my application I get the real user ip like so:

String clientIP = request.getHeader("X-Real-IP");
BaDr Amer
  • 820
  • 11
  • 29
6

Below is the Spring way, with autowired request bean in @Controller class:

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());
Leon
  • 3,124
  • 31
  • 36
  • 4
    This could cause issues with concurrent use of the controller across multiple threads. Only singletons should be injected into `@Controller` instances using `@Autowired`. Otherwise, you must use `@Scope(BeanDefinition.SCOPE_PROTOTYPE)` on the controller class to ensure that a new instance of the controller is made with every request. This is less efficient, but is a workaround if you must inject something as a property to the controller class. – Andy Aug 19 '19 at 17:12
6

Put this method in your 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
  • 3,716
  • 1
  • 30
  • 28
6

See below. This code works with spring-boot and 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
  • 131
  • 2
  • 5
3
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();
    }

I combie the code above to this code work for most case. Pass the HttpServletRequest request you get from the api to the method

Kyo Huu
  • 520
  • 7
  • 13
0

In my case, I am using this piece of code:

private String getRemoteAddr(HttpServletRequest req) {
    if (!StringUtils.isEmpty(req.getHeader("X-Real-IP"))) {
        return req.getHeader("X-Real-IP");
    }
    return req.getRemoteAddr();
}
Ulug'bek
  • 2,762
  • 6
  • 31
  • 59
0

In my case request.getRemoteAddr() contains the IP address of system from which user is trying to access the application. and in case, if I am running my application on localhost or 127.0.0.1 it is returning "0:0:0:0:0:0:0:1"

Harsh
  • 23
  • 1
  • 5