본문 바로가기

서버/SprintBoot
[스프링부트(Spring Boot)] 소셜 로그인(네이버 로그인)

네이버 API 는 처음 사용해 보는 거라 , 애플리케이션 생성부터 차근차근 시작했다.

https://developers.naver.com/products/login/api/api.md

 

네이버 로그인 - INTRO

환영합니다 네이버 로그인의 올바른 적용방법을 알아볼까요? 네이버 로그인을 통해 신규 회원을 늘리고, 기존 회원은 간편하게 로그인하게 하려면 제대로 적용하는 것이 중요합니다! 이에 올바

developers.naver.com

 

카카오랑 생성하는 게 비슷하다! 

차이점이, 카카오는 얻어올 수 있는 사용자의 정보가 제한되어 있었는데(아마 개인이라) 네이버는 거의 다 받아올 수 있는 듯 하다.

하지만 나는 카카오랑 동일한 소셜 로그인 처리를 하기 위해 이메일만 선택했다.

Callback URL은 카카오의 Redirect URI 와 동일한 역할.

Client ID와 Client Secret을 발급받았다.


아래 페이지에서 네이버 버튼 이미지를 받아준다.

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

 

로그인 버튼 사용 가이드 - LOGIN

네이버 로그인은 애플리케이션에 사용할 수 있는 네이버 로그인 버튼 기본 이미지를 제공합니다. 애플리케이션의 상황에 맞게 버튼 이미지의 디자인을 변경할 수 있지만 네이버 고유의 아이덴

developers.naver.com


나는 카카오 로그인과 이미지를 맞추었다.


흐름이 카카오 로그인과 동일하기 때문에 비교적 수월하게 진행했다.

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

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

 

네이버 로그인 API 명세 - LOGIN

네이버 로그인 API 명세 네이버 로그인 API는 네이버 로그인 인증 요청 API, 접근 토큰 발급/갱신/삭제 요청API로 구성되어 있습니다. 네이버 로그인 인증 요청 API는 여러분의 웹 또는 앱에 네이버

developers.naver.com

1. 인가 코드 받아오기

1) Redirect URI 등록한 대로 컴포넌트 만들기

카카오와 네이버의 흐름이 같은 줄 알았다면 통일했을 텐데, 그걸 몰라서 따로 구분하였다.

우선은 공부하면서 각각 해보고, 끝난 후 리팩토링할 예정.

{
    path: '/naver-login',
    name: 'naver',
    component: () => import('@/components/NaverLogin.vue')
  },


2) URL 연결하기

버튼 클릭 시 인가 코드 받아오도록 하기

naverLogin() {
      const url = 'https://nid.naver.com/oauth2.0/authorize';
      location.href = `${url}?client_id=${this.naverLoginParams.client_id}&redirect_uri=${this.naverLoginParams.redirect_uri}&response_type=${this.naverLoginParams.response_type}&state=${this.naverLoginParams.state}`;
    },


넘겨줄 param들은 data에 정의해두었다.

naverLoginParams: {
        client_id: process.env.VUE_APP_NAVER_CLIENT_ID,
        redirect_uri: process.env.VUE_APP_NAVER_REDIRECT_URI,
        response_type: 'code',
        state: this.generateEncodedState(),
      }
  1. client_id: 네이버 개발자센터에서 발급받은 client ID
  2. redirect_uri: 네이버 개발자센터에서 설정한 Redirect URI
  3. response_type: 'code'로 고정
  4. scope: 상태 토큰값(URL 인코딩 값) 

카카오와 마찬가지로 client_id나 redirect_uri 는 .env 파일에 저장하고 꺼내썼다.

참고로. 검수요청을 통해 승인을 받아야 애플리케이션을 생성한 계정 말고 다른 계정도 로그인할 수 있다.


2. 토큰 받아오기

조금 전에 받아온 인가 코드를 활용해서 post 요청을 보내야 한다.

카카오의 경우, 클라이언트에서 바로 처리가 가능했지만 네이버는 그게 안 된다..

무조건 서버에서 토큰을 받아올 수 있다. 

리팩토링하면서 카카오도 서버로 넘길 예정..

인가코드를 post요청으로 서버에 넘기고, 서버에서 다시 post으로 토큰 받아온 후 클라이언트에 반환.

tokenParams: {
        client_id: process.env.VUE_APP_NAVER_CLIENT_ID,
        client_secret: process.env.VUE_APP_NAVER_CLIENT_SECRET_ID,
        code: this.$route.query.code,
        grant_type : 'authorization_code',
        state: this.generateEncodedState(),
      },
      
      ...
      
  await axios.post(this.$store.state.url+'naverlogin', new URLSearchParams(this.tokenParams).toString())
        .then(response => {
          this.token.access_token = response.data.result.access_token;
          this.token.refresh_token = response.data.result.refresh_token;
        })
        .catch(error => {
          console.log(error);
        })
  1. client_id: 네이버 개발자센터에서 발급받은 clientid
  2. client_secret: 네이버 개발자센터에서 발급받은 client secret id
  3. grant_type: 'authorization_code'로 고정
  4. code: 인가 코드
  5. state: U$RL 인코딩 값(임의의 문자열)

이번에도 역시 data에 정의해두고 매개변수를 넘겼다.(URL에 붙여서)

서버: 컨트롤러 > 서비스로 넘기고, 서비스에서 post 요청

try {
            URI uri = new URI("https://nid.naver.com/oauth2.0/token?"+params );
            NaverTokenDTO response = restTemplate.postForObject(uri, null, NaverTokenDTO.class);

            if (response != null) {
                rModel.setState(true);
                rModel.setMessage("네이버 로그인에 성공했습니다.");
                rModel.setResult(response);
            } else {
                rModel.setState(false);
                rModel.setMessage("네이버 로그인 응답을 받지 못했습니다.");
            }
        } catch (URISyntaxException e) {
            rModel.setState(false);
            rModel.setMessage("잘못된 URI 형식입니다.");
        } catch (Exception e) {
            rModel.setState(false);
            rModel.setMessage("네이버 로그인 중 오류가 발생했습니다: " + e.getMessage());
        }

3. 로그인한 사용자 정보 받아오기

이번에도 역시 서버 측에서 get 요청을 해야 한다.

헤더 설정하여 서버로 보내고, 서버에서 받아서 처리한다.

const userConfig = {
      headers: {
        'Authorization' : `Bearer ${this.token.access_token}`,
      }
    }

    await axios.get(this.$store.state.url+'naverlogin', userConfig)
        .then(response => {
          this.$store.commit('setSnsUserId', response.data.result.response.id)
          this.$store.commit('setSnsUserEmail', response.data.result.response.email)

          this.userinfo.id = response.data.id;

          axios.post(this.$store.state.url + 'dup', this.userinfo)
              .then(response => {
                console.log(response.data.result.length);
                if(response.data.result.length == 0) {
                  this.$router.push({name: 'sns'})
                } else {
                  sessionStorage.setItem('id', this.userinfo.id);
                  this.getUserinfo();
                }
              })
              .catch(error => {
                console.log(error);
              })

        })
        .catch(error => {
          console.log(error);
          Swal.fire({
            title: '로그인에 실패했습니다.',
            icon: 'error'
          });
        })

 

try {
            URI uri = new URI("https://openapi.naver.com/v1/nid/me");

            // 헤더 설정
            HttpHeaders headers = new HttpHeaders();
            headers.set("Authorization", header);
            HttpEntity<String> entity = new HttpEntity<>("parameters", headers);

            ResponseEntity<Object> response = restTemplate.exchange(uri, HttpMethod.GET, entity, Object.class);

            if (response.getBody() != null) {
                rModel.setState(true);
                rModel.setMessage("네이버 로그인에 성공했습니다.");
                rModel.setResult(response.getBody());
            } else {
                rModel.setState(false);
                rModel.setMessage("네이버 로그인 응답을 받지 못했습니다.");
            }
        } catch (URISyntaxException e) {
            rModel.setState(false);
            rModel.setMessage("잘못된 URI 형식입니다.");
        } catch (Exception e) {
            rModel.setState(false);
            rModel.setMessage("네이버 로그인 중 오류가 발생했습니다: " + e.getMessage());
        }

최초 로그인일 경우 추가 정보 입력을 위해 회원가입 진행.

아이디와 이메일은 네이버 계정에서 받아온 것 그대로 넣기(수정 불가)

네이버의 경우 아이디가 길기 때문에 DB에서 자료형 길이를 충분히 주길.

기존에 가입한 회원의 로그인일 경우 바로 일반 로그인과 같은 로직으로 로그인 처리.