¿Cómo extraer la dirección IP en Spring MVC Controller get call?

93

Estoy trabajando en el proyecto del controlador Spring MVC en el que estoy haciendo una llamada GET URL desde el navegador -

A continuación se muestra la URL con la que estoy haciendo una llamada GET desde el navegador:

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

Y a continuación se muestra el código en el que se produce la llamada después de presionar en el navegador:

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

Planteamiento del problema:-

Ahora, ¿hay alguna forma de que pueda extraer la dirección IP de algún encabezado? Lo que significa que me gustaría saber de qué dirección IP viene la llamada, es decir, quienquiera que llame por encima de la URL, necesito saber su dirección IP. ¿Es posible hacer esto?

Juan
fuente
Intente usar Spring AOP y manejar HttpServletRequest. stackoverflow.com/questions/19271807/…
Dilip G

Respuestas:

148

La solucion es

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

Agregue HttpServletRequest requesta la definición de su método y luego use la API de Servlet

Spring Documentation aquí dicho en

15.3.2.3 Argumentos y tipos de retorno de métodos de controlador admitidos

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
fuente
1
Gracias Koitoer por la ayuda. Una pregunta rápida, suponga que si la llamada proviene de Load Balancer en lugar de una máquina específica, ¿esto también funcionará? Supongo que no ...
john
No, no lo hará, pero hay alguna configuración en el balanceador de carga que puede enviar la IP ya que no existe, probablemente este sea tu caso
Koitoer
Verifique que probablemente el equilibrador de carga pueda enviar esos valores en un encabezado, así que considere usar el método getHeader de HttpServletRequest.
Koitoer
Koitoer ¡¡Funciona perfectamente !! Pero hay otra forma en lugar de HttpServletRequest.
Harshal Patil
1
Esto está desaprobado.
Gewure
112

Llego tarde aquí, pero esto podría ayudar a alguien que busque la respuesta. Normalmente servletRequest.getRemoteAddr()funciona.

En muchos casos, los usuarios de su aplicación pueden estar accediendo a su servidor web a través de un servidor proxy o tal vez su aplicación esté detrás de un equilibrador de carga.

Por lo tanto, debe acceder al encabezado http X-Fordered-For en tal caso para obtener la dirección IP del usuario.

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

Espero que esto ayude.

sunitkatkar
fuente
11
Tenga en cuenta que X-Forwarded-Forgeneralmente es una lista de ips separados por comas, con cada proxy en la cadena agregando la dirección remota que ve a la lista. Entonces, una buena implementación generalmente tendría una lista de proxies confiables y "omitir" esos ips al leer este encabezado de derecha a izquierda.
Raman
cómo obtener la dirección IP como 111.111.111.111/X
Muneeb Mirza
26

Yo uso ese método para hacer esto

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
fuente
1
donde lo uso
Maifee Ul Asad
12

Puede obtener la dirección IP de forma estática de la RequestContextHoldersiguiente manera:

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

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

Pon este método en tu 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
fuente
4

Vea abajo. Este código funciona con spring-boot y 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
fuente
3

A continuación se muestra la forma de Spring, con un autowiredbean de solicitud en la @Controllerclase:

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());
León
fuente
1
Esto podría causar problemas con el uso simultáneo del controlador en varios subprocesos. Solo se deben inyectar singletons en @Controllerinstancias usando @Autowired. De lo contrario, debe usar @Scope(BeanDefinition.SCOPE_PROTOTYPE)en la clase de controlador para asegurarse de que se realice una nueva instancia del controlador con cada solicitud. Esto es menos eficiente, pero es una solución si debe inyectar algo como una propiedad en la clase del controlador.
Andy
1

En mi caso, estaba usando Nginx frente a mi aplicación con la siguiente configuración:

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

así que en mi aplicación obtengo la IP del usuario real así:

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

Combino el código anterior para que este código funcione en la mayoría de los casos. Pasa lo HttpServletRequest requestque obtienes de la api al método

Kyo Huu
fuente