본문 바로가기
▶ Back-End/Java

SNS 간편로그인 - 네이버 로그인 API 호출 및 사용자 정보 받기

by 오늘도 코딩 2024. 7. 16.
728x90
반응형

Spring Boot에서 RestTemplate을 통해 네이버 Open API를 호출하여 사용자 정보 받기

*SNS 간편로그인 - 네이버 API 사용 등록 방법 완료 후 진행(관련 글 참고)

*프로세스는 카카오와 구글 모두 동일

*Swagger3 관련 소스 포함

*자세한 설명 생략

 

 

▷ application.properties 설정

#NAVER
naver.client.id="NAVER에서 제공한 Client ID"
naver.client.secret="NAVER에서 제공한 Client Secret"
naver.redirect.uri="NAVER에 설정한 Redirect URI"

 

 

▷ naver.html

*로그인 화면(간단히 버튼만 생성)

<!DOCTYPE html>
<html>
<head>
   <meta charset="UTF-8">
   <title>네이버 테스트 페이지</title>
</head>
<body>
   <div align="center">
      <h1>네이버 로그인 테스트</h1><br><br>
      
      <a th:href="
         @{https://nid.naver.com/oauth2.0/authorize(
              client_id=${clientId},
              redirect_uri=${redirectUri},
              response_type=${responseType},
              state=${state}
              )}">
         <img src="/images/naver_login_btn.png">
      </a>
   </div>
</body>
</html>

 

 

▷ CmmUtil.java

*공통 유틸리티

/**
 * 공통 유틸리티
 */
public class CmmUtil {

   /**
     * 
     * Object to String
     * 
     * @param Object
     * @return String
     * @throws JsonProcessingException
     */
    public static String getObjStr(Object obj) throws JsonProcessingException {
        return new ObjectMapper()
                .registerModule(new JavaTimeModule())
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .writeValueAsString(obj);
    }
}

 

 

▷ NaverController.java

*로그인 화면 진입 Controller 생성

/**
 * 네이버 TEST Controller
 */
@Controller
@RequestMapping("test")
public class NaverContrller {
   
   @Value("${naver.client.id}")
   private String NAVER_CLIENT_ID;

   @Value("${naver.redirect.uri}")
   private String NAVER_REDIRECT_URI;

   @GetMapping("/naver.do")
    public String kakaoLogin(Model model){
      
        model.addAttribute("clientId", NAVER_CLIENT_ID);
        model.addAttribute("redirectUri", NAVER_REDIRECT_URI);
        model.addAttribute("responseType", "code");
        model.addAttribute("state", "STATE_STRING");
        
        return "naver";
    }
   
}

 

 

▷ LGN1003Controller.java

*Redirect Controller 생성

/**
 * 네이버 Login Controller
 */
@Slf4j
@RestController
@RequestMapping("xxxx")
@Tag(name = "LGN", description = "Login Controller")
public class LGN1003Controller {

   @Autowired
   private LGNService lgnService;

   @GetMapping("/naver/login.do")
   @Operation(summary = "XXXX-LGN-1003", description = "[네이버] 로그인(Redirect)")
   public LGN1003ResVO lgn1003(@Parameter(description = "인가 코드") @RequestParam("code") String code) {

      LGN1003ResVO resVO = new LGN1003ResVO();

      try {

         resVO = lgnService.getLGN1003(code);

         log.info("[네이버] 로그인 최종 응답");
         log.info(CmmUtil.getObjStr(resVO));
      } catch (Exception e) {
         
      }

      return resVO;
   }

}

 

 

▷ LGN1003ResVO.java

*최종 응답 VO

/**
 * [네이버] 로그인 응답 VO
 */
@Getter
@Setter
@ToString
@Schema(description = "[네이버] 로그인 응답 VO")
public class LGN1003ResVO extends CmmResVO {

   /** 결과 값 */
   @JsonProperty("result")
   @Schema(description = "결과 값")
   public LGN1003VO result;

   @Getter
   @Setter
   @ToString
   @Schema(description = "[네이버] 로그인 응답 VO")
   public static class LGN1003VO {

      @Schema(description = "API 호출 결과 코드")
      @JsonProperty("resultcode")
      public String resultCode;

      @Schema(description = "호출 결과 메시지")
      @JsonProperty("message")
      public String message;

      @Schema(description = "동일인 식별 정보")
      @JsonProperty("response")
      public Response response;

      @Getter
      @Setter
      @ToString
      @Schema(description = "[네이버] 동일인 식별 정보 VO")
      public static class Response {

         @Schema(description = "동일인 식별 정보는 네이버 아이디마다 고유하게 발급되는 값입니다.")
         @JsonProperty("id")
         public String id;

         @Schema(description = "사용자 별명")
         @JsonProperty("nickname")
         public String nickname;

         @Schema(description = "사용자 이름")
         @JsonProperty("name")
         public String name;

         @Schema(description = "사용자 메일 주소")
         @JsonProperty("email")
         public String email;

         @Schema(description = "성별")
         @JsonProperty("gender")
         public String gender;

         @Schema(description = "사용자 연령대")
         @JsonProperty("age")
         public String age;

         @Schema(description = "사용자 생일(MM-DD 형식)")
         @JsonProperty("birthday")
         public String birthday;

         @Schema(description = "사용자 프로필 사진 URL")
         @JsonProperty("profile_image")
         public String profileImage;

         @Schema(description = "출생연도")
         @JsonProperty("birthyear")
         public String birthyear;

         @Schema(description = "휴대전화번호")
         @JsonProperty("mobile")
         public String mobile;

         @Schema(description = "휴대전화번호의 E.164 형식")
         @JsonProperty("mobile_e164")
         public String mobileE164;
      }

   }

}

 

 

▷ CmmResVO.java

*공통 응답

/**
 * 공통 응답 VO
 */
@Getter
@Setter
@ToString
@Schema(description = "공통 응답 VO")
public class CmmResVO {

    /** Result Code */
    @JsonProperty("resultCode")
    @Schema(description = "Result Code")
    public String resultCode = "0000";

    /** Result Msg */
    @JsonProperty("resultMsg")
    @Schema(description = "Result Msg")
    public String resultMsg = "성공";

    /** Set Result */
    public CmmResVO setResCmmResult(String resultCode, String resultMsg) {
        this.resultCode = resultCode;
        this.resultMsg = resultMsg;

        return this;
    }
}

 

 

▷ LGNService.java

/**
 * Login Service
 */
public interface LGNService {
   
   /** [네이버] 로그인 **/
   public LGN1003ResVO getLGN1003(String code);
}

 

 

▷ LGNServiceImpl.java

/**
 * Login ServiceImpl
 *
 */
@Service
public class LGNServiceImpl implements LGNService {

   @Autowired
   private NaverApiService naverApi;

   /**
    * [네이버] 로그인
    */
   @Override
   public LGN1003ResVO getLGN1003(String code) {

      LGN1003ResVO result = new LGN1003ResVO();

      try {
         /* [네이버] 토큰 발급 */
         NaverOAuthTokenVO token = naverApi.getOAuthToken(code);

         /* [네이버] 사용자 정보 조회 */
         NaverUserInfoVO userInfo = naverApi.getUserInfo(token.getAccess_token());

         /* 사용자 정보 저장 */

         /* 응답 값 설정 */
         Response response = new Response();
         response.setId(userInfo.getResponse().getId());
         response.setNickname(userInfo.getResponse().getNickname());
         response.setName(userInfo.getResponse().getName());
         response.setEmail(userInfo.getResponse().getEmail());
         response.setGender(userInfo.getResponse().getGender());
         response.setAge(userInfo.getResponse().getAge());
         response.setBirthday(userInfo.getResponse().getBirthday());
         response.setProfileImage(userInfo.getResponse().getProfileImage());
         response.setBirthyear(userInfo.getResponse().getBirthyear());
         response.setMobile(userInfo.getResponse().getMobile());
         response.setMobileE164(userInfo.getResponse().getMobileE164());

         LGN1003VO vo = new LGN1003VO();
         vo.setResultCode(userInfo.getResultCode());
         vo.setMessage(userInfo.getMessage());
         vo.setResponse(response);

         result.setResult(vo);

      } catch (Exception e) {
         
      }

      return result;
   }

}

 

 

▷ NaverOAuthTokenVO.java

/**
 * [네이버] 토큰 발급 응답 VO
 */
@Getter
@Setter
@ToString
@Schema(description = "[네이버] 토큰 발급 응답 VO")
@JsonIgnoreProperties(ignoreUnknown = true)
public class NaverOAuthTokenVO {

   @JsonProperty("access_token")
   @Schema(description = "접근 토큰, 발급 후 expires_in 파라미터에 설정된 시간(초)이 지나면 만료됨")
   public String access_token;
   
   @JsonProperty("refresh_token")
   @Schema(description = "갱신 토큰, 접근 토큰이 만료될 경우 접근 토큰을 다시 발급받을 때 사용")
   public String refresh_token;
   
}

 

 

▷ NaverUserInfoVO.java

/**
 * [네이버] 사용자 정보 조회 응답 VO
 */
@Getter
@Setter
@ToString
@Schema(description = "[네이버] 사용자 정보 조회 응답 VO")
@JsonIgnoreProperties(ignoreUnknown = true)
public class NaverUserInfoVO {

   @Schema(description = "API 호출 결과 코드")
   @JsonProperty("resultcode")
   public String resultCode;

   @Schema(description = "호출 결과 메시지")
   @JsonProperty("message")
   public String message;

   @Schema(description = "동일인 식별 정보")
   @JsonProperty("response")
   public Response response;

   @Getter
   @Setter
   @ToString
   @Schema(description = "[네이버] 동일인 식별 정보 VO")
   @JsonIgnoreProperties(ignoreUnknown = true)
   public static class Response {

      @Schema(description = "동일인 식별 정보는 네이버 아이디마다 고유하게 발급되는 값입니다.")
      @JsonProperty("id")
      public String id;

      @Schema(description = "사용자 별명")
      @JsonProperty("nickname")
      public String nickname;

      @Schema(description = "사용자 이름")
      @JsonProperty("name")
      public String name;

      @Schema(description = "사용자 메일 주소")
      @JsonProperty("email")
      public String email;

      @Schema(description = "성별", allowableValues = { "F", "M", "U" })
      @JsonProperty("gender")
      public String gender;

      @Schema(description = "사용자 연령대")
      @JsonProperty("age")
      public String age;

      @Schema(description = "사용자 생일(MM-DD 형식)")
      @JsonProperty("birthday")
      public String birthday;

      @Schema(description = "사용자 프로필 사진 URL")
      @JsonProperty("profile_image")
      public String profileImage;

      @Schema(description = "출생연도")
      @JsonProperty("birthyear")
      public String birthyear;

      @Schema(description = "휴대전화번호")
      @JsonProperty("mobile")
      public String mobile;
      
      @Schema(description = "휴대전화번호의 E.164 형식")
        @JsonProperty("mobile_e164")
        public String mobileE164;
   }

}

 

 

▷ NaverApiService.java

/**
 * 네이버 API Service
 * 
 * https://developers.naver.com/docs/login/devguide/devguide.md
 */
public interface NaverApiService {
   
   /** [네이버] 토큰 발급 **/
   public NaverOAuthTokenVO getOAuthToken(String code);
   
   /** [네이버] 사용자 정보 조회 **/
   public NaverUserInfoVO getUserInfo(String accessToken);
   
}

 

 

▷ NaverApiServiceImpl.java

/**
 * 네이버 API ServiceImpl
 *
 */
@Slf4j
@Service
public class NaverApiServiceImpl implements NaverApiService {

   @Value("${naver.client.id}")
   private String NAVER_CLIENT_ID;

   @Value("${naver.client.secret}")
   private String NAVER_API_SECRET;

   @Value("${naver.redirect.uri}")
   private String NAVER_REDIRECT_URI;

   /**
    * [네이버] 토큰 발급
    */
   @Override
   public NaverOAuthTokenVO getOAuthToken(String code) {

      NaverOAuthTokenVO result = new NaverOAuthTokenVO();

      try {
         log.info("[네이버] 토큰 발급 시작");

         if (code == null) {
            return result;
         }

         /* 요청 */
         final String uri = "https://nid.naver.com/oauth2.0/token";

         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); // MultiValueMap

         MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
         body.add("grant_type", "authorization_code");
         body.add("client_id", NAVER_CLIENT_ID);
         body.add("client_secret", NAVER_API_SECRET);
         body.add("redirect_uri", NAVER_REDIRECT_URI);
         body.add("code", code);

         /* 응답 */
         ResponseEntity<String> res = new RestTemplate().postForEntity(uri, new HttpEntity<>(body, headers), String.class);
         result = new ObjectMapper().readValue(res.getBody(), NaverOAuthTokenVO.class);

         log.info("[네이버] 토큰 발급 종료");
      } catch (Exception e) {
         
      }

      return result;
   }

   /**
    * [네이버] 사용자 정보 조회
    */
   @Override
   public NaverUserInfoVO getUserInfo(String accessToken) {

      NaverUserInfoVO result = new NaverUserInfoVO();

      try {
         log.info("[네이버] 사용자 정보 조회 시작");

         if (accessToken == null) {
            return result;
         }

         /* 요청 */
         final String uri = "https://openapi.naver.com/v1/nid/me";

         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); // MultiValueMap
         headers.add("Authorization", "Bearer " + accessToken);

         /* 응답 */
         ResponseEntity<String> res = new RestTemplate().postForEntity(uri, new HttpEntity<>(headers), String.class);
         result = new ObjectMapper().readValue(res.getBody(), NaverUserInfoVO.class);

         log.info("[네이버] 사용자 정보 조회 종료");
      } catch (Exception e) {
         log.error("", e);
         
      }

      return result;
   }

}

 

 

▷ 결과

소스가 수정됨에 결과화면과 다를수 있음

 

 

▷ 관련 글

 

SNS 간편로그인 - 네이버 API 사용 등록 방법

네이버 Open API를 사용하기 위한 네이버 developers 앱 등록*자세한 설명 생략  ▷ 네이버 API 사용 등록 방법 ① 내 애플리케이션 생성 애플리케이션 - NAVER Developers developers.naver.com  ▷ 관련 글 S

coding-today.tistory.com

 

RestTemplate Post 요청 보내기

RestTemplate로 Post 요청을 보내고, 응답 코드를 확인하는 메서드*Header 값(Authorization)만 추가하고, Body는 빈 값으로 요청*자세한 설명 생략   /** * POST 요청 */public static boolean sendPost(String jwt) { boolean r

coding-today.tistory.com

 

Objcet to String

Object를 String으로 변환하는 간단한 방법 /** * * Object to String * * @param Object * @return String */ public static String getObjStr(Object obj) { String str = ""; try { str = new ObjectMapper().writeValueAsString(obj); } catch (Exception e)

coding-today.tistory.com

 

JSON Unrecognized field 해결방법(@JsonIgnoreProperties)

JSON 데이터를 구성하는 요소가 가변적일 때 무시하는 방법 *소스는 변하지 않았지만 연동 했던 API 응답 값이 변했다고 가정 ▷ ERROR - JSON 데이터를 매핑하지 못해 에러 발생 com.fasterxml.jackson.databi

coding-today.tistory.com

 

SNS 간편로그인 - 카카오 API 사용 등록 방법

카카오 Open API를 사용하기 위한 카카오 developers 앱 등록*자세한 설명 생략  ▷ 카카오 API 사용 등록 방법  ① 내 애플리케이션 생성 Kakao Developers카카오 API를 활용하여 다양한 어플리케이션을

coding-today.tistory.com

 

SNS 간편로그인 - 구글 API 사용 등록 방법

구글 Open API를 사용하기 위한 구글 developers 사용 설정*자세한 설명 생략  ▷ 구글  API 사용 등록 방법 ⓛ 프로젝트 생성 Google 클라우드 플랫폼로그인 Google 클라우드 플랫폼으로 이동accounts.goog

coding-today.tistory.com

 

 

▷ 참고

 

애플리케이션 - NAVER Developers

 

developers.naver.com

 

네이버 로그인 개발가이드 - LOGIN

네이버 로그인 개발가이드 1. 개요 4,200만 네이버 회원을 여러분의 사용자로! 네이버 회원이라면, 여러분의 사이트를 간편하게 이용할 수 있습니다. 전 국민 모두가 가지고 있는 네이버 아이디

developers.naver.com

 

 

728x90
728x90

댓글