ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스프링 부트 네이버 소셜 로그인
    졸업과제/BackEnd 2023. 5. 12. 16:05

    네이버 로그인 API 서비스 등록

    https://developers.naver.com/apps/#/myapps/TCaKGyOMHwb8QZ0oSMyV/overview

     

    애플리케이션 - NAVER Developers

     

    developers.naver.com

    네이버 개발자센터에 들어가서 서비스를 하고자 하는 URL과 네이버 로그인 API를 호출할 URL들을 명시하여 준다.

     

    /naver_callback URL은 네이버 계정으로 회원가입할때 호출할 예정이고

    /naver_login은 네이버 계정으로 로그인할때 호출할 예정이여서 2가지 URL을 등록해두었다.

     

    동의 항목

    제공 받고자 하는 목록을 선택하여 줄 수 있다. 우리 서비스는 사용자가 정보 제공을 동의하면 사용자로부터 인가를 받은 상태가 되어

    네이버 서버가 사용자의 정보를 제공하여 줄 수 있다.


    Naver 로그인 URI 호출하기.

    로그인 URI 호출 방법.

    https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=QWER12341234&state=APPLEBANANA&redirect_uri=http://localhost:8081/naver_callback

    네이버 로그인 API를 이용하기 첫번째 단계는 Naver 로그인 API를 호출하는 것이다.

    기재 되어있는 URI로 4개의 요청 변수를 전달해야 한다.

    • reponse_type : code( 그냥 code 라고 적으면 된다)
    • client_id : 서비스 등록할때 발급 받은 Client ID
    • redirect_uri : 등록해두었던 CallBack URI
    • state : 서비스 등록할때 발급 받은 Client Secret

    로그인 API 호출 완료

    로그인 화면이 나오고 사용자가 로그인을 완료하고 동의항목에 대해서 동의를 성공적으로 수행하면

    callback URI에 code값과 state값이 문자열로 전송된다.

    우리는 Spring을 사용하기 때문에 이제 Controller에서 @GetMapping으로 callback URI를 받은 다음에 code값과 state값으로 Token을 요청해야 한다.


    Naver OAuthToken 발급받기

     

    요청해야하는 URI와 요청 변수들

    네이버 계정 정보를 얻기 위해 Token을 발급 받아야 한다 이때 요청해야 하는 URI와 요청 변수는 다음과 같다.

    • 요청 URI : https://nid.naver.com/oauth2.0/token
    • grant_type : 상황에 맞는 구분값 입력. 발급 받을 것이기 때문에 'authorization_code' 명시
    • client_id : 서비스 등록시 발급받은 Client ID 값
    • client_secret : 서비스 등록시 발급 받은 Client secret 값
    • code : API 호출에 성공하고 callback URI 문자열에 실려서 넘어온 code 값
    • state: API 호출에 성공하고 callback URI 문자열에 실려서 넘어온 state 값

     

    public NaverProfile getNaverProfile(String code, String state)
    {
        RestTemplate rt = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
    
    	// 요청 변수 세팅
        LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("grant_type", "authorization_code");
        params.add("client_id", "apple");
        params.add("client_secret", "banana");
        params.add("code", code);
        params.add("state", state);
    
        HttpEntity<MultiValueMap<String, String>> naver_token_request =
                new HttpEntity<>(params,headers);
    
    	//요쳥 변수를 담아 token 요청
        ResponseEntity<String> response = rt.exchange(
                "https://nid.naver.com/oauth2.0/token",
                HttpMethod.POST,
                naver_token_request,
                String.class
        );
    }

    공식 문서에 나와있던대로 값을 세팅해서 전송해준다. 

    전송이 성공했다면 네이버 서버에서 JSON 형식으로 Token 값을 담아서 돌려준다.

    다음 과정은 JSON 형식으로 넘어온 Token응답 정보를 Parsing해서 객체로 변환하는 과정이 필요하다.

     

    Token 응답 정보

    // Token 응답 정보를 받을 Class
    @Data
    public class NaverOAuthToken 
    {
        private String access_token;
        private String refresh_token;
        private String token_type;
        private Integer expires_in;
        private String error;
        private String error_description;
    }
    ObjectMapper objectMapper = new ObjectMapper();
    NaverOAuthToken oAuthToken = null;
    try {
        oAuthToken = objectMapper.readValue(response.getBody(), NaverOAuthToken.class);
    } catch (JsonMappingException e) {
        e.printStackTrace();
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }

    JSON 형식으로 넘어온 Token 정보를 만들어둔 NaverOAtuhToken 클래스에 담아낸다.

    네이버로부터 사용자 개인정보에 접근할 수 있는 Token을 발급받았기 때문에 다음 과정은 Token을 이용해 

    우리가 필요한 사용자의 개인정보를 받아올 수 있다.


    Token을 이용해 사용자 개인정보 받아오기

    사용자 개인정보 받아오기

    발급된 access_token을 이용해 네이버 프로필 API를 호출할때 필요한 정보는 다음과 같다.

    Token을 발급받을때 와는 달리 요청변수가 필요없고 요청 헤더에 발급받은 access_token을 전달해주면 된다.

     

    HttpHeaders headers2 = new HttpHeaders();
    // 요청 헤더에 Bearer access_token 담기
    headers2.add("Authorization","Bearer "+oAuthToken.getAccess_token());
    
    HttpEntity<MultiValueMap<String, String>> naver_profile_request =
            new HttpEntity<>(headers2);
    
    // 프로필 API에 요청 헤더 전달
    ResponseEntity<String> naver_profile_response = rt.exchange(
            "https://openapi.naver.com/v1/nid/me",
            HttpMethod.POST,
            naver_profile_request,
            String.class

    요청이 성공적으로 수행됬다면 계정 프로필에 대한 값이 JSON 형태로 naver_profile_response에 담겨져 있을 것이다.

    이제 다음과정은 Token을 객체로 parsing했던것과 같은 방식으로 응답 결과에 맞는 객체를 생성해서 객체로 담아내면 된다.

     

     

    naver_profile_response 파싱 결과(우), 공식 문서에 기재되어있는 출력결과(좌)

     

    응답해준 결과를 보면 하나의 JSON객체 안에 response라는 JSON 객체가 또 있는 구조로 되어있는 모습을 확인할 수 있다.

    따라서 응답 결과를 받아낼 클래스를 만들때에도 응답 결과와 같은 구조로 클래스를 만들어서 생성해줘야 오류가 안난다.

     

     

    @Data
    @JsonIgnoreProperties(ignoreUnknown=true)
    public class NaverProfile {
    
        private String resultcode;
        private String message;
        
        //inner class로 Response 클래스 선언
        private Response response;
        
        @JsonIgnoreProperties(ignoreUnknown=true)
        @Data
        public class Response{
            private String id;
            private String nickname;
            private String name;
            private String email;
            private String gender;
            private String birthday;
            private String birthyear;
            private String profile_image;
            private String mobile;
            private String mobile_e164;
    
        }
    }
    NaverProfile naverProfile = null;
    
    try {
    // JSON 형식으로 넘어온 계정 정보를 객체로 변환
        naverProfile = objectMapper.readValue(naver_profile_response.getBody(), NaverProfile.class);
    } catch (JsonMappingException e) {
        e.printStackTrace();
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    
    // 계정 정보가 담긴 객체 return
    return naverProfile;

    마지막으로 JSON 형식으로 되어있는 프로필 정보를 만들어두었던 객체로 변환하면 끝이다.


    전체 코드

     

    @Controller
    public class SocialController
    {
        @GetMapping(value = "/naver_callback")
        public void NaverSocialSignUp(String code, String state, RedirectAttributes attr)
        {
            logger.info("[NaverSocialLogin] 네이버 계정으로 회원가입 컨트롤러 동작");
            NaverProfile naverProfile = socialService.getNaverProfile(code, state);
        }
    }
    @Service
    public class SocialService
    {
    	public NaverProfile getNaverProfile(String code, String state)
        {
            logger.info("[getNaverProfile] 네이버 서버로부터 네이버 계정 정보 얻는 로직 시작.");
            RestTemplate rt = new RestTemplate();
            HttpHeaders headers = new HttpHeaders();
    
            LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>();
            params.add("grant_type", "authorization_code");
            params.add("client_id", "TCaKGyOMHwb8QZ0oSMyV");
            params.add("client_secret", "k9iThEg12Q");
            params.add("code", code);
            params.add("state", state);
    
            HttpEntity<MultiValueMap<String, String>> naver_token_request =
                    new HttpEntity<>(params,headers);
    
    
            ResponseEntity<String> response = rt.exchange(
                    "https://nid.naver.com/oauth2.0/token",
                    HttpMethod.POST,
                    naver_token_request,
                    String.class
            );
    
            ObjectMapper objectMapper = new ObjectMapper();
            NaverOAuthToken oAuthToken = null;
            try {
                oAuthToken = objectMapper.readValue(response.getBody(), NaverOAuthToken.class);
            } catch (JsonMappingException e) {
                e.printStackTrace();
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
    
    
            HttpHeaders headers2 = new HttpHeaders();
            headers2.add("Authorization","Bearer "+oAuthToken.getAccess_token());
    
            HttpEntity<MultiValueMap<String, String>> naver_profile_request =
                    new HttpEntity<>(headers2);
    
    
            ResponseEntity<String> naver_profile_response = rt.exchange(
                    "https://openapi.naver.com/v1/nid/me",
                    HttpMethod.POST,
                    naver_profile_request,
                    String.class
            );
            logger.info("네이버 프로필 JSON : {}",naver_profile_response);
    
            NaverProfile naverProfile = null;
    
            try {
                naverProfile = objectMapper.readValue(naver_profile_response.getBody(), NaverProfile.class);
            } catch (JsonMappingException e) {
                e.printStackTrace();
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
    
            return naverProfile;
        }
    }

     


    카카오와 네이버 로그인 API를 성공적으로 구현을 완료하였다.

    말로만 듣던 API를 실제 다뤄보니 생각보다 어렵지 않네? 라는 생각이 들었다. 글로만 읽었을 때는 머리에 제대로 들어오지도 않고

    OAuth2.0의 전반적인 흐름도 이해가 가지 않았지만 역시 직접 코드로 두들겨야 이해가 조금이나마 간다.

     

    API 사용에 대한 두려움이 조금은 사라진거 같다.

    이번 소셜로그인 구현을 통해 오픈 API를 호출하는 법과 JSON을 객체로 파싱하는 법등을 알아간거 같아서 보람차다.

     

    댓글

Designed by Tistory.