How to extract IP Address in Spring MVC Controller get call?
Asked Answered
C

11

149

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?

Checkerwork answered 5/4, 2014 at 6:21 Comment(1)
Try using Spring AOP and handling HttpServletRequest. #19272307Decrescendo
P
194

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
Pantomime answered 5/4, 2014 at 6:33 Comment(9)
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..Checkerwork
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 casePantomime
Check probably load balancer can send those values in a header, so consider using getHeader method of HttpServletRequest.Pantomime
Koitoer It works perfectly!! But there is any other way rather than HttpServletRequest.Chaldron
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 objectPantomime
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?Schonfeld
I'm also getting 0:0:0:0:0:0:0:1Omaomaha
This is deprecated.Nutting
@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?Isaiah
M
144

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");

Murvyn answered 15/4, 2015 at 3:55 Comment(5)
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.Toolmaker
how to get ip address as 111.111.111.111/XCredent
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 propertyOster
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?Valor
Spring boot is able to automatically resolve the forwarded IP address for you. See this question for details.Hydrology
E
61

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();
    }
}
Eadith answered 20/3, 2019 at 17:30 Comment(4)
where do i use it ?Sandpiper
It is a static class, it uses the name of the class and the method ip = HttpReqRespUtils.getClientIpAddressIfServletRequestExist();Dalmatic
For those who are wondering why return 0.0.0.0 when RequestContextHolder.getRequestAttributes() == null, see 0.0.0.0 - Wikipedia.Encourage
Add if (ip.equals("0:0:0:0:0:0:0:1")) ip = "127.0.0.1"; before return ip statement in the above code to make it IPv4 complaint.Firstly
S
19

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

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

String ip = request.getRemoteAddr();
Sideslip answered 21/5, 2017 at 15:9 Comment(0)
G
8

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());

:)

Gemeinschaft answered 3/11, 2019 at 17:7 Comment(0)
M
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");
Mcdonough answered 29/4, 2020 at 5:58 Comment(1)
Thank you sir. It's a graceful solution that helped me.Linoleum
T
6

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

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());
Tacitus answered 6/3, 2019 at 14:15 Comment(1)
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.Sikang
S
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;
}
Seritaserjeant answered 10/8, 2019 at 12:38 Comment(0)
P
4
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

Plangent answered 25/6, 2020 at 16:33 Comment(0)
B
1

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"

Brookhouse answered 28/11, 2022 at 6:15 Comment(0)
U
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();
}
Unbent answered 12/1, 2022 at 6:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.