Web Programming

네이버 로그인 쉽게 구현하기 3편 - 로그인 구현하기 (SpringBoot + Vue.js)

놋수저 2023. 1. 22. 12:47
반응형

로그인 처리 플로우는 아래와 같다.

 

인가 코드 받기 -> 토큰 받기 -> 사용자 정보 가져오기

해당 글에서는 인가 코드 받기는 클라이언트 페이지에서, 토큰 받기 사용자 정보 가져오기는 서버에서 처리할 예정이다.

위 플로우 대로 처리되기 위해 2개의 클라이언트 페이지와 1개의 API가 필요하다.

1. 클라이언트 페이지

  • 네이버 로그인 버튼 페이지
  • 네이버 로그인 후 Redirect되는 페이지

2. 서버

  • 클라이언트 페이지에서 전달받은 인가코드를 통해 로그인 토큰 발급 및 유저 정보를 조회하는 API

네이버 인증 구현

1. 인가 코드 받기

서비스 서버가 네이버 인증 서버로 인가 코드 받기를 요청한다. 여기서 얻은 인가 코드는 로그인 토큰을 얻기 위해 사용된다.

클라이언트 페이지에서 네이버 로그인창이 노출되고 네이버 계정으로 로그인한 후 앞서 설정한 Redirect URL로 redirect될 때 인가코드를 확인할 수 있다.

 

2. 토큰 받기

앞서 얻은 인가 코드로 로그인 토큰 발급을 요청한다. 토큰 받기를 마쳐야 네이버 로그인을 정상적으로 완료할 수 있다. 해당 토큰으로 로그인이 유효한지 판단할 수 있으며 각 토큰의 역할과 만료 시간에 대한 자세한 정보는 토큰 정보에서 확인할 수 있다. 액세스 토큰의 경우, 토큰 정보 보기로 토큰 유효성을 검사하거나 리프레시 토큰을 사용해 갱신할 수 있다.

 

3. 사용자 정보 가져오기

앞서 얻은 액세스 토큰을 헤더에 담아 사용자 정보를 가져올 수 있다.

 

위 과정 외에도 토큰 갱신, 로그아웃 등의 추가적으로 제공하는 API가 있지만 해당 글에서는 로그인 구현을 위해 필수로 사용해야하는 API만 사용할 예정이다.

인가 코드 받기

네이버 로그인창을 노출시키는 방법은 앞서 네이버 개발자센터에서 발급받은 Key와 Redirect URL 등을 파라미터에 추가하여 호출하면 된다.

 

doNaverLogin() {
  const url = 'https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=' +
      process.env.VUE_APP_NAVER_CLIENT_ID +
      '&redirect_uri=' +
      process.env.VUE_APP_NAVER_REDIRECT_URL +
      '&state=1234';

  this.showSocialLoginPopup(url)
},

위 함수는 네이버 로그인창을 호출하는 함수이다.

네이버 로그인창을 호출하는 URL은 https://nid.naver.com/oauth2.0/authorize 이다.

필수로 추가해야하는 파라미터는 response_type, client_id, redirect_uri, state 총 4개가 있다.

  • client_id: 네이버 개발자센터에서 발급받은 JavaScript Key
  • redirect_uri: 네이버 개발자센터에서 설정한 Callback URI
  • response_type: 'code'로 고정 (인가코드를 통한 로그인 방식)
  • state: 사이트 간 요청 위조(cross-site request forgery) 공격을 방지하기 위해 애플리케이션에서 생성한 상태 토큰값으로 URL 인코딩을 적용한 값을 사용한다. 자바스크립트에서 제공하는 Encode를 사용하는 것이 좋지만, 간결한 테스트를 위해 해당 과정은 skip하겠다.

요청문 샘플

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

 

더 자세한 내용은 네이버 API 문서에서 상세하게 확인할 수 있다

https://developers.naver.com/docs/login/devguide/devguide.md#%EB%84%A4%EC%9D%B4%EB%B2%84%20%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B0%9C%EB%B0%9C%EA%B0%80%EC%9D%B4%EB%93%9C

 

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

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

developers.naver.com

 

파라미터 요청 값을 올바르게 설정했을 경우 네이버 로그인 페이지가 노출된다.

 

 

로그인에 성공하면 앞서 설정한 동의 항목이 노출된다.

 

 

동의항목 설정을 완료하면 앞서 네이버 개발자 센터에서 설정한 Callback URL로 네이버에서 Callback 해준다.

 

 

로그인 성공 후 Redirect URL은 아래와 같이 설정된다.

http://localhost:8080/naver-login?code=21oRCTQqdjC020hPom&state=1234

http://localhost:8080/naver-login은 네이버 개발자센터에서 설정한 Callback URL이며 그 뒤에는 code라는 이름의 파라미터가 존재한다. 여기서 code를 이용해 로그인 처리에 필요한 토큰을 얻을 수 있다.

로그인 토큰 얻기

인가 코드는 로그인 토큰을 얻기 위한 코드일 뿐 로그인 처리가 완료된 것이 아니다. 로그인 토큰까지 발급되어야 정상적으로 로그인 처리가 완료된다.

앞서 클라이언트 페이지에서 얻은 인가 코드를 통해 로그인에 필요한 토큰을 얻을 수 있다.

인가 코드를 통해 로그인 토큰을 가져오는 API 이다. 클라이언트 페이지에서 얻은 인가 코드를 API Body에 전달한다.

@RestController
@RequestMapping("/api/user")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @PostMapping("/social-login")
    public ResponseEntity<LoginResponse> doSocialLogin(@RequestBody @Valid SocialLoginRequest request) {

        return ResponseEntity.created(URI.create("/social-login"))
                .body(userService.doSocialLogin(request));
    }

네이버 인증 서버에서 로그인 토큰을 가져온다.

요청 URI은 https://nid.naver.com/oauth2.0/token 이다.

로그인 토큰을 가져오기 위해 5개의 파라미터를 설정해야 한다.

  • grant_type : 클라이언트 페이지에서 얻은 인가 코드를 사용 하기 때문에 "code"로 고정. 
  • client_id : 네이버 개발자센터에서 발급 받은 Client ID
  • client_secret : 네이버 개발자센터에서 발급 받은 Client Secret
  • code : 클라이언트 페이지에서 얻은 인가 코드
  • state: 사이트 간 요청 위조(cross-site request forgery) 공격을 방지하기 위해 애플리케이션에서 생성한 상태 토큰값으로 URL 인코딩을 적용한 값을 사용한다. 자바스크립트에서 제공하는 Encode를 사용하는 것이 좋지만, 간결한 테스트를 위해 해당 과정은 클라이언트에서 설정한 "1234" 값으로 설정하겠다.
@FeignClient(value = "naverAuth", url="https://nid.naver.com", configuration = {FeignConfiguration.class})
public interface NaverAuthApi {
    @GetMapping("/oauth2.0/token")
    ResponseEntity<String> getAccessToken(
            @RequestParam("grant_type") String grantType,
            @RequestParam("client_id") String clientId,
            @RequestParam("client_secret") String clientSecret,
            @RequestParam("code") String code,
            @RequestParam("state") String state
    );
}

 

정상적으로 응답받았을 때의 응답 데이터는 아래와 같다.

{
  "access_token": "AAAANrrD1gf6VdJPp6M7mwCg4mCcMT2hDj1EbRezSiJiG9vZkVnsXgEwxMcUmei4oeA5z96SbTNPeAgfvKCx6BHao5M",
  "refresh_token": "O5foipurgYgTIC0NCFUTqJyrBWCzk7n0q1BoipisqOFcz9WgwkT2c307X2TDAwNUQvXrDsuLEV8nMPosQyfXNT7fMeoV3CUp73V1isMepPIu33J7vZjBKLBLfVo2mskvCDu0",
  "token_type": "bearer",
  "expires_in": "3600"
}
  • access_token: 사용자 액세스 토큰 값
  • refresh_token: 사용자 리프레시 토큰 값
  • token_type: 토큰 타입, Bearer로 고정
  • expires_in: 액세스 토큰의 만료시간 (초)

위 과정을 통해 로그인 처리를 완료하였다. 토큰의 만료시간이 정해져 있으므로 필요에 따라 토큰 갱신 API를 이용하면 된다.

여기서 얻은 accss_token으로 앞서 설정한 동의 항목을 바탕으로 로그인한 유저의 정보를 가져올 수 있다.

유저 정보 가져오기

위 과정에서 발급 받은 액세스 토큰으로 유저 정보를 가져올 수 있다.

네이버 서버에서 유저 정보를 가져온 후 필요에 따라 만들고자 하는 서비스에서 회원가입 또는 로그인 처리를 할 수 있다.

유저 정보 조회 API는 헤더에 앞서 발급받은 액세스 토큰을 넣어주어야 한다.

@Override
public SocialUserResponse getUserInfo(String accessToken) {
  Map<String ,String> headerMap = new HashMap<>();
  headerMap.put("authorization", "Bearer " + accessToken);

  ResponseEntity<?> response = naverUserApi.getUserInfo(headerMap);

액세스 토큰 앞에 "Bearer" + 공백 한 칸(" ")을 더한 값을 헤더에 담아 요청해야 한다.

@FeignClient(value = "naverUser", url="https://openapi.naver.com", configuration = {FeignConfiguration.class})
public interface NaverUserApi {
    @GetMapping("/v1/nid/me")
    ResponseEntity<String> getUserInfo(@RequestHeader Map<String, String> header);
}

요청 URI는 https://openapi.naver.com/v1/nid/me 이다.

정상적으로 응답받았을 때의 응답 데이터는 아래와 같다.

{
  "resultcode": "00",
  "message": "success",
  "response": {
    "id": "P_VRcMphOGnVKRfG0bcMLvwkCidc5tB_MnpvPU0-7sQ",
    "nickname": "\uc724\uc131\ud638",
    "profile_image": "https:\/\/ssl.pstatic.net\/static\/pwe\/address\/img_profile.png",
    "age": "30-39",
    "gender": "M",
    "email": "dune93@naver.com",
    "name": "\uc724\uc131\ud638",
    "birthday": "07-31",
    "birthyear": "1993"
  },

네이버 개발자센터에서 설정한 동의 항목들의 데이터가 응답된다 😄

네이버 유저 정보를 응답받은 이후에는 구현하고자 하는 서비스 로직에 따라 원하는 코드를 추가하면된다.

if (userRepository.findByUserId(socialUserResponse.getId()).isEmpty()) {
    this.joinUser(
            UserJoinRequest.builder()
                    .userId(socialUserResponse.getId())
                    .userEmail(socialUserResponse.getEmail())
                    .userName(socialUserResponse.getName())
                    .userType(request.getUserType())
                    .build()
    );
}

 

네이버는 API 문서가 정말 잘 정리 되어있어 구현하기가 정말 쉬웠다.

참고로 최초 로그인 이후, 그 다음 부터는 동의 항목 없이 자동으로 넘어간다.

 

아래는 SNS 로그인 구현한 소스코드 링크이다. 카카오 로그인도 구현되어 있으니 소셜로그인 연동 개발 하시는 분들은 참고하셔도 좋을 것 같다 😄

 

소스코드

https://github.com/vvsungho/social-login-view

 

GitHub - vvsungho/social-login-view: 소셜 로그인 클라이언트 화면

소셜 로그인 클라이언트 화면. Contribute to vvsungho/social-login-view development by creating an account on GitHub.

github.com

https://github.com/vvsungho/social-login-server

 

GitHub - vvsungho/social-login-server: 소셜 로그인 서버

소셜 로그인 서버. Contribute to vvsungho/social-login-server development by creating an account on GitHub.

github.com

 

관련글

https://notspoon.tistory.com/41

 

네이버 로그인 쉽게 구현하기 1편 - Naver Developers 설정

네이버 로그인 API 클라이언트 입장에서 수많은 사이트의 모든 아이디 비밀번호를 기억하기는 쉽지 않다. 또한 서비스를 제공해주는 리소스 오너 또한 안전하게 보관하여야 하기 때문에 부담된

notspoon.tistory.com

https://notspoon.tistory.com/42

 

네이버 로그인 쉽게 구현하기 2편 - 개발 환경 설정

개발환경 Spring Boot Vue.js MySQL 필요한 모듈 설치 Java 11 vue/cli 4.5.4 MySQL 8.0.18 Java, Vue, MySQL 버전은 위와 상이해도 무관하다. 1. Spring Boot 프로젝트 생성 1) Spring Boot 프로젝트 생성 아래 사이트에서 Spr

notspoon.tistory.com

반응형
LIST