Backend/JAVA

[JAVA] Client IP, Device Type 추출 (IP 기반 로그인)

dddzr 2025. 12. 18. 06:37

📌 1. Client IP 추출 방법

📖 getClientIp 예제

public String getClientIp(HttpServletRequest request){

       String ip = request.getHeader("X-Forwarded-For");      

       //1️⃣여러 IP가 있을 경우 첫 번째 IP만 사용
       if (ip != null && ip.contains(",")) {
           ip = ip.split(",")[0].trim();
       }
     
       //2️⃣기타 프록시 관련 헤더 확인
       if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getHeader("Proxy-Client-IP");
       }

       if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getHeader("WL-Proxy-Client-IP");
       }

       if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getHeader("HTTP_CLIENT_IP");
       }

       if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getHeader("HTTP_X_FORWARDED_FOR");
       }

       if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getHeader("X-Real-IP");
       }

       if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getHeader("X-RealIP");
       }

       if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getHeader("REMOTE_ADDR");
       }

       if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
           ip = request.getRemoteAddr();
       }

       //3️⃣IPv6 loopback 또는 localhost 처리
       if ("0:0:0:0:0:0:0:1".equals(ip) || "127.0.0.1".equals(ip)) {
           InetAddress address;
           
            //4️⃣예외 처리
            try {
                address = InetAddress.getLocalHost();
                ip = address.getHostAddress(); //address.getHostName()

            } catch (UnknownHostException e) {
                e.printStackTrace();
                ip = "127.0.0.1";
            }
       }

       //5️⃣로깅
       logger.info("Client IP: {}", ip);
       return ip;

   }

1️⃣X-Forwarded-For 안에 여러 IP가 들어올 때 분리해서 처리

2️⃣헤더 순서대로 진짜 IP를 찾음.

3️⃣로컬호스트일 경우에는 getLocalHost()를 써서 IP + 호스트명을 반환

4️⃣UnknownHostException 처리

5️⃣Ip 로깅

 

📌 X-Forwarded-For란?

클라이언트가 HTTP 요청을 보낼 때,  프록시 서버(예: Nginx, AWS ALB 등)가
클라이언트 IP를 보존하기 위해 이 헤더에 IP를 붙여서 전달함.

 

📌 여러 IP가 들어오는 이유?

요청이 여러 프록시를 통과할수록, 프록시마다 X-Forwarded-For에 IP를 추가하기 때문.

📖 예시:

X-Forwarded-For: 123.45.67.89, 10.0.0.1, 172.31.255.3

✔️123.45.67.89: 진짜 클라이언트 IP (브라우저가 쏜 IP)

✔️10.0.0.1: 첫 번째 프록시 서버

✔️172.31.255.3: 두 번째 프록시 서버

 

📌 2. 다중 디바이스 환경에서 IP 기반 로그인

✅ 2-1. 최근 로그인된 IP 리스트 관리 (화이트리스트 방식)

  • USER_ID 기준으로 최근 사용한 IP 최대 3개까지 저장
  • 로그인 시 등록된 IP 중 하나면 허용
  • 새로운 IP에서 접근 시
    추가 인증 요청 (예: 2차 인증, 이메일 알림 등)

✅ 2-2. Access Token + IP 매핑 방식 (디바이스 단위로)

  • ACCESS_TOKENUSER_ID를 기준으로 IP 하나 매핑됨
  • 로그인 시 토큰이 유효하더라도, 요청한 IP가 해당 토큰에 저장된 IP와 다르면 재로그인 유도

 

✅ 2-3. 다비이스 타입 + IP 매핑

  • DB컬럼에 디바이스 타입 추가(예: MOBILE_YN)
  • User-Agent에서 디바이스 정보를 추출
  • 최신순 정렬, limit 1해서 디바이스 타입별 최근 1개 IP가져옴.

 

🔍 User-Agent란?

  •  User-Agent는 클라이언트(브라우저나 앱)가 서버에 요청을 보낼 때 자신의 정보를 담아서 보내는 HTTP 헤더.
  • User-Agent가 담고 있는 정보: 브라우저(Chrome, Edge 등), 운영체제(Windows, Android, iOS 등), 디바이스(모바일, 태블릿, PC 등), 기타(웹 버전, 웹킷 등)

 

📖 디바이스 타입 구분 예제

   public static String isMobile(HttpServletRequest req) {   
   
    String userAgent = req.getHeader("User-Agent").toUpperCase();
    String[] mobileKeywords = {
               "ANDROID", "IPHONE", "IPAD", "IPOD", "MOBILE", "MOBI"
       };   
    logger.info("userAgent: {}", userAgent);

    if (userAgent != null) {
           userAgent = userAgent.toUpperCase();
           for (String keyword : mobileKeywords) {
               if (userAgent.contains(keyword)) {
                   return "Y";
               }
           }
       }
       return "N";
   }


'Backend > JAVA' 카테고리의 다른 글

Streaming이란?  (0) 2025.12.18
json파일 읽기  (0) 2025.12.18
대량 DB INSERT 최적화  (0) 2025.11.29
파일 업로드, 다운로드 (MultipartFile)  (0) 2025.11.08
JUnit 단위 테스트 적용, JaCoCo 커버리지 측정  (0) 2025.08.27