네이버 애플리케이션 등록

네이버 소셜 로그인 기능을 사용하기 위해서는 네이버 디벨로퍼스에서 네이버 애플리케이션 등록이 필요하다.

https://developers.naver.com/

 

NAVER Developers

네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음

developers.naver.com

 

디벨로퍼스에 가입을 하고 Application -> 애플리케이션 등록으로 이동한다.

권한 중 필요한 것을 추가한다.

필수로 체크한 것은 최초 로그인 시 제공 동의를 받게 된다. 

 

아래에서 PC 웹 환경울 추가하고 서비스 URL(로컬 프로젝트라 로컬 호스트 사용)와 콜백 URL을 추가한다.

콜백 URL은 클라이언트에서 네이버 로그인 후 콜백을 받은 URL이란 뜻.

등록을 완료하면 애플리케이션 정보로 이동해 Client ID와 Client Secret을 확인한다.

미리 환경 변수로 등록 해두자.

 

 

전체적인 흐름

자세한 것은 네이버 로그인 개발가이드 참고. 개인적으로 타사 api에 비해 설명이 더 잘 되어있다 느꼈다.

https://developers.naver.com/docs/login/devguide/devguide.md

 

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

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

developers.naver.com

 

네이버 로그인을 수행하고 회원 정보를 가져오기 까지의 흐름은 아래와 같다.

  1. 네이버 로그인 연동 후 Callback 받기
  2. Callback에서 받은 code로 접근 토큰 발급 요청 
  3. 접근 토큰을 이용하여 프로필 API 호출하기

해당 순서대로 하나하나 살펴본다.

 

 

네이버 로그인 연동 후 Callback 받기

 

우선 네이버 로그인을 요청할 URL을 작성해야 한다.

기본 URL은 위와 같고 요청 변수 정보에 해당하는 쿼리 파라미터를 넣어 URL을 만들어야 한다.

 

요청문 샘플

https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=CLIENT_ID&state=STATE_STRING&redirect_uri=CALLBACK_URL

 

이후 우리가 등록한 콜백 URL로 응답이 오게 된다.

여기서 code는 접근 토큰을 받기 위해 다음 단계 요청에서 쓰이게 된다.

 

login.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="utf-8">
    <title>네이버 로그인</title>
</head>
<body>
<a href="/naver/login">
    <button>네이버 로그인</button>
</a>
</body>
</html>

우선 네이버 로그인 버튼을 누르면 해당 주소로 리다이렉트 하도록 하였다.

 

SocialOauthController

@RestController
@RequiredArgsConstructor
public class SocialOauthController {

    private final NaverOauthService naverOauthService;
    private final NaverUserService naverUserService;

    @ResponseBody
    @GetMapping("/api/auth/social/login")
    public ResponseEntity<?> socialCallback(
            @RequestParam("code") String code,
            @RequestParam("state") String state
    ) {
        NaverProfileResponseDto.NaverUserDetail detail = this.naverOauthService.getNaverUserDetails(code, state);
        return ResponseEntity.ok(naverUserService.naverLogin(detail));
    }

    @GetMapping("/naver/login")
    public void naverLogin(HttpServletRequest request, HttpServletResponse response) {
        try {
            response.sendRedirect(naverOauthService.generateUrl());
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

컨트롤러에서는 방금 리다이렉트로 설정한 url로 요청이 들어오면

요청문 샘플에 맞춰 url을 만들어 또다시 리다이렉트 한다.

 

서비스의 Url 생성 메서드

    public String generateUrl() throws UnsupportedEncodingException {
        return UriComponentsBuilder.fromHttpUrl(naverProperties.getNaverPopupUrl())
                .queryParam("response_type", "code")
                .queryParam("client_id", naverProperties.getNaverClientId())
                .queryParam("state", URLEncoder.encode(UUID.randomUUID().toString().substring(0, 8), "UTF-8"))
                .queryParam("redirect_uri", URLEncoder.encode(naverProperties.getNaverRedirectUrl(), "UTF-8"))
                .build().toUriString();
    }

유저가 네이버 로그인을 하면 애플리케이션에서 설정한 콜백 url로 응답이 들어오게 된다.

여기서 토큰 발급에 필요한 인증 코드를 받을 수 있다.

 

 

Callback에서 받은 code로 접근 토큰 발급 요청 

 

요청문 샘플

https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&client_id=jyvqXeaVOVmV&client_secret=527300A0_COq1_XV33cf&code=EIc5bFrl4RibFls1&state=9kgsGTfH4j7IyAkg

 

이번엔 인증 코드로 토큰을 발급 받을 것이다.

필수 파라미터와 발급 때 필수인 파라미터를 조합하여 요청문을 완성한다.

 

 

서비스의 토큰 발급 과정

    public NaverProfileResponseDto.NaverUserDetail getNaverUserDetails(String code, String state) {
        NaverTokenResponseDto tokenResponseDto = this.getToken(code, state);
        return this.getUser(tokenResponseDto.getAccess_token());
    }

    private NaverTokenResponseDto getToken(String code, String state) {
        RestTemplate restTemplate = new RestTemplate();

        String url = UriComponentsBuilder.fromHttpUrl(naverProperties.getNaverTokenUrl())
                .queryParam("grant_type", "authorization_code")
                .queryParam("client_id", naverProperties.getNaverClientId())
                .queryParam("client_secret", naverProperties.getNaverClientSecret())
                .queryParam("code", code)
                .queryParam("state", state)
                .build().toUriString();

        ResponseEntity<NaverTokenResponseDto> responseDto = restTemplate.postForEntity(url, null, NaverTokenResponseDto.class);

        return responseDto.getBody();
    }

RestTemplate을 사용해 토큰을 발급하였다.

 

응답 정보에 맞는 형태로 Dto 객체를 생성하였다.

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class NaverTokenResponseDto {
    private String access_token;
    private String refresh_token;
    private String token_type;
    private int expires_in;
    private String error;
    private String error_description;
}

 

우리는 여기서 access_token만 사용할 것이다.

 

 

접근 토큰을 이용하여 프로필 API 호출하기

 

요청문 예시

curl -XGET "https://openapi.naver.com/v1/nid/me" \ -H "Authorization: Bearer AAAAPIuf0L+qfDkMABQ3IJ8heq2mlw71DojBj3oc2Z6OxMQESVSrtR0dbvsiQbPbP1/cxva23n7mQShtfK4pchdk/rc="

 

출력 결과는 더 많은 항목이 있으나 길이 문제로 잘랐다. 직접 가서 확인 바란다.

우리 프로젝트에서는 nickname, email만 사용하고 있다.

 

서비스의 프로필 획득 과정

    private NaverProfileResponseDto.NaverUserDetail getUser(String token) {
        RestTemplate restTemplate = new RestTemplate();

        String url = naverProperties.getNaverProfileUrl();

        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(token);
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(headers);
        ResponseEntity<NaverProfileResponseDto> responseDto = restTemplate.exchange(url, HttpMethod.GET, request, NaverProfileResponseDto.class);

        return responseDto.getBody().getResponse();
    }

여기서도 RestTemplate을 사용해 요청을 보냈다.

아까와는 다르게 헤더가 필요하기 때문에 메서드의 모양새가 조금 다르다.

 

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class NaverProfileResponseDto {
    private String resultcode;
    private String message;

    private NaverUserDetail response;

    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    public static class NaverUserDetail {
        private String id;
        private String nickname;
        private String email;
    }
}

네이버에서는 response 안에 프로필 정보를 포함하고 있으니 계층 구조로 Dto를 설계해야 한다.

 

 

이후 과정

@Service
@RequiredArgsConstructor
public class NaverUserService {

    private final UserService userService;
    private final JwtUtil jwtUtil;

    public LoginTokenDto naverLogin(NaverProfileResponseDto.NaverUserDetail naverUserDetail) {
        User user = null;

        try {
            user = userService.getUserByEmail(naverUserDetail.getEmail());
        } catch (Exception e) {
            UserSignupRequestDto dto = new UserSignupRequestDto();
            dto.setEmail(naverUserDetail.getEmail());
            dto.setName(naverUserDetail.getNickname());
            dto.setPassword(UUID.randomUUID().toString().substring(0, 8));
            user = userService.signup(dto);
        }

        return LoginTokenDto.builder()
                .accessToken(jwtUtil.createAccessToken(user))
                .build();
    }
}

우리는 이렇게 받은 이메일과 이름 정보를 가지고 DB에 이메일 정보가 있는지 확인하여 없으면 회원가입, 있으면 바로 access 토큰을 발급해주고 있다.

여기서 부터는 각자 서비스에 맞춰 이후 로직을 개발 하면 될 것 같다!

 

다음에는 스프링 시큐리티의 OAuth2 라이브러리를 사용한 소셜 로그인으로 돌아오도록 하겠다.

+ Recent posts