Spring MVC Controller에서 IP 주소를 추출하는 방법은 무엇입니까?


93

브라우저에서 GET URL 호출을 만드는 Spring MVC 컨트롤러 프로젝트에서 작업 중입니다.

아래는 브라우저에서 GET 호출을하는 URL입니다.

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

그리고 아래는 브라우저를 쳐서 호출이 오는 코드입니다.

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

문제 설명:-

이제 어떤 방법으로 헤더에서 IP 주소를 추출 할 수 있습니까? 즉, 어떤 IP 주소에서 전화가 오는지 알고 싶습니다. 즉, URL 위의 전화를 거는 사람이 누구든지 해당 IP 주소를 알아야합니다. 이것이 가능합니까?


Spring AOP를 사용하고 HttpServletRequest를 처리하십시오. stackoverflow.com/questions/19271807/…
Dilip G

답변:


148

해결책은

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

HttpServletRequest request메서드 정의에 추가 한 다음 Servlet API를 사용합니다.

여기에 봄 문서가 말했다

15.3.2.3 지원되는 핸들러 메서드 인수 및 반환 유형

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

1
도움을 주신 Koitoer에게 감사드립니다. 한 가지 간단한 질문으로, 호출이 특정 시스템이 아닌 Load Balancer에서 오는 경우 이것도 작동한다고 가정하십시오. 그럴 것 같아요 ..

아니요,하지만로드 밸런서에 존재하지 않는 IP를 보낼 수있는 구성이 있습니다. 아마도 이것은 귀하의 경우 일 것입니다
Koitoer

로드 밸런서가 해당 값을 헤더로 보낼 수 있는지 확인하므로 HttpServletRequest의 getHeader 메소드를 사용하는 것이 좋습니다.
Koitoer 2014

Koitoer 완벽하게 작동합니다 !! 그러나 HttpServletRequest 대신 다른 방법이 있습니다.
Harshal Patil 2014

1
더 이상 사용되지 않습니다.
Gewure

112

나는 여기에 늦었지만 이것은 누군가가 답을 찾는 데 도움이 될 수 있습니다. 일반적으로 servletRequest.getRemoteAddr()작동합니다.

대부분의 경우 애플리케이션 사용자가 프록시 서버를 통해 웹 서버에 액세스하거나 애플리케이션이로드 밸런서 뒤에있을 수 있습니다.

따라서 사용자의 IP 주소를 얻으려면 이러한 경우 X-Forwarded-For http 헤더에 액세스해야 합니다.

예 : String ipAddress = request.getHeader("X-FORWARDED-FOR");

도움이 되었기를 바랍니다.


11
참고 X-Forwarded-For가 목록에 볼 원격 주소 부가 체인의 각 프록시에 일반적으로 IPS 쉼표로 구분된다. 따라서 좋은 구현은 일반적으로 신뢰할 수있는 프록시 목록을 갖고이 헤더를 오른쪽에서 왼쪽으로 읽을 때 해당 IP를 "건너 뛰십시오".
Raman

111.111.111.111/X로 주소 IP를 활용하는 방법
Muneeb 미르자

26

나는 이것을하기 위해 그런 방법을 사용한다

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

1
어디서 사용합니까?
Maifee Ul Asad

12

RequestContextHolder아래와 같이 IP 주소를 정적으로 얻을 수 있습니다 .

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

String ip = request.getRemoteAddr();

4

이 메소드를 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;
}

4

아래를 참조하십시오. 이 코드는 spring-boot 및 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());

:)


3

다음은 클래스에 autowired요청 빈이 있는 Spring 방식입니다 @Controller.

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());

1
이로 인해 여러 스레드에서 컨트롤러를 동시에 사용하는 데 문제가 발생할 수 있습니다. .NET을 @Controller사용 하는 인스턴스에 싱글 톤 만 주입해야합니다 @Autowired. 그렇지 않으면 @Scope(BeanDefinition.SCOPE_PROTOTYPE)컨트롤러 클래스에서를 사용하여 모든 요청에 ​​대해 컨트롤러의 새 인스턴스가 만들어 지도록해야합니다. 이 방법은 덜 효율적이지만 컨트롤러 클래스에 속성으로 무언가를 주입해야하는 경우 해결 방법입니다.
Andy

1

제 경우에는 다음 구성으로 응용 프로그램 앞에서 Nginx를 사용했습니다.

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

그래서 내 응용 프로그램에서 실제 사용자 IP를 다음과 같이 얻습니다.

String clientIP = request.getHeader("X-Real-IP");

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

위의 코드를이 코드와 결합하여 대부분의 경우 작동합니다. 패스 HttpServletRequest request는 방법으로 API에서 얻을

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.