Como extrair o endereço IP no Spring MVC Controller get call?

94

Estou trabalhando no projeto do controlador Spring MVC no qual estou fazendo uma chamada GET URL do navegador -

Abaixo está o url pelo qual estou fazendo uma chamada GET do navegador -

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

E abaixo está o código em que a chamada vem depois de acessar o 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
    }

Declaração do problema: -

Agora, há alguma maneira de extrair o endereço IP de algum cabeçalho? Significa que gostaria de saber de qual endereço IP a chamada está vindo, ou seja, quem está ligando acima do URL, preciso saber seu endereço IP. Isso é possível fazer?

John
fonte
Tente usar Spring AOP e manipular HttpServletRequest. stackoverflow.com/questions/19271807/…
Dilip G

Respostas:

153

A solução é

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

Adicione HttpServletRequest requestà sua definição de método e, em seguida, use a API Servlet

A documentação da primavera aqui disse em

15.3.2.3 Argumentos de método manipulador suportados e tipos de retorno

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
fonte
1
Obrigado Koitoer pela ajuda. Uma pergunta rápida: suponha que se a chamada vier do Load Balancer em vez de uma máquina específica, isso também funcionará. Acho que não ..
john,
Não, não vai, mas há algumas configurações no balanceador de carga que podem enviar o IP como eles não existem, provavelmente este é o seu caso
Koitoer
Verifique se o balanceador de carga pode enviar esses valores em um cabeçalho, portanto, considere usar o método getHeader de HttpServletRequest.
Koitoer,
Koitoer Funciona perfeitamente !! Mas há qualquer outra maneira além de HttpServletRequest.
Harshal Patil,
1
Isso está obsoleto.
Gewure de
114

Estou atrasado aqui, mas isso pode ajudar alguém que esteja procurando a resposta. Normalmente servletRequest.getRemoteAddr()funciona.

Em muitos casos, os usuários do seu aplicativo podem estar acessando seu servidor da web por meio de um servidor proxy ou talvez seu aplicativo esteja atrás de um balanceador de carga.

Portanto, você deve acessar o cabeçalho X-Forwarded-For http nesse caso para obter o endereço IP do usuário.

por exemplo String ipAddress = request.getHeader("X-FORWARDED-FOR");

Espero que isto ajude.

sunitkatkar
fonte
11
Observe que X-Forwarded-Forgeralmente é uma lista separada por vírgulas de ips, com cada proxy na cadeia adicionando o endereço remoto que vê à lista. Portanto, uma boa implementação geralmente teria uma lista de proxies confiáveis ​​e "pularia" esses ips ao ler este cabeçalho da direita para a esquerda.
Raman
como obter o endereço IP como 111.111.111.111/X
Muneeb Mirza
Observe que o Tomcat, por exemplo, RemoteIpValveanalisa o X-Forwarded-Forcabeçalho e o define no HttpServletRequest, de modo que servletRequest.getRemoteAddr()retorna o endereço IP correto do usuário final. No Spring Boot pode ser habilitado através da server.tomcat.remote-ip-header=X-Forwarded-Forpropriedade do aplicativo
Gediminas Rimsa
26

Eu uso esse método para fazer isso

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
fonte
1
onde eu uso?
Maifee Ul Asad
12

Você pode obter o endereço IP estaticamente a partir do RequestContextHolderseguinte:

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

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

Coloque este método em seu 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
fonte
4

Ver abaixo. Este código funciona com spring-boot e 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
fonte
3

Abaixo está o método Spring, com o autowiredbean de solicitação na @Controllerclasse:

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());
Leon
fonte
1
Isso pode causar problemas com o uso simultâneo do controlador em vários threads. Apenas singletons devem ser injetados em @Controllerinstâncias usando @Autowired. Caso contrário, você deve usar @Scope(BeanDefinition.SCOPE_PROTOTYPE)na classe do controlador para garantir que uma nova instância do controlador seja feita com cada solicitação. Isso é menos eficiente, mas é uma solução alternativa se você precisar injetar algo como uma propriedade na classe do controlador.
Andy
1

No meu caso, estava usando o Nginx na frente do meu aplicativo com a seguinte configuração:

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

então, em meu aplicativo, obtenho o ip do usuário real assim:

String clientIP = request.getHeader("X-Real-IP");
BaDr Amer
fonte
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 o código acima para que este código funcione na maioria dos casos. Passe o que HttpServletRequest requestvocê obtém da api para o método

Kyo Huu
fonte