본문 바로가기
개발

네이버 로그인

by ^..^v 2023. 4. 6.
728x90
반응형

MySQL, React, SpringBoot로 구현한 게시판 서비스에 네이버 아이디로 로그인 기능을 추가하는 과정으로, 실습에 사용한 코드는 https://myanjini.tistory.com/entry/board-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C 에서 내려받을 수 있습니다. 

 

애플리케이션 등록

네이버 개발자 사이트(https://developers.naver.com/)에서 애플리케이션을 등록하고, API를 설정합니다. 

사용 API로 네이버 로그인을 선택하고, 로그인 성공 시 제공받을 정보를 선택합니다.

 

서비스 환경으로 PC 웹을 선택하고, 서비스 URL, Callback URL을 지정합니다.

 

 

라이브러리 등록

SDK 다운로드 페이지(https://developers.naver.com/docs/login/sdks/sdks.md)에서 JavaScript용 네이버 로그인 라이브러리의 최신 버전 링크 주소를 확인합니다. 

 

index.html 파일에 앞에서 복사한 링크 주소를 src 속성 값으로 갖는 <script> 태그를 추가합니다. 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
			... (생략) ... 
    <!-- JavaScript용 네이버 로그인 라이브러리 추가 -->
    <script type="text/javascript" src="https://static.nid.naver.com/js/naveridlogin_js_sdk_2.0.2.js" charset="utf-8"></script>
  </head>
  <body>
  			... (생략) ... 
  </body>
</html>

 

네이버 로그인 컴포넌트 추가

NaverLogin.js 파일을 생성하고, 아래 코드를 추가합니다. 해당 코드는 샘플 페이지(https://static.nid.naver.com/oauth/sample/javascript_sample.html)의 소스코드를 참고해서 작성했습니다.

import { useEffect } from "react";

const NaverLogin = () => {
    // window 객체로 부터 naver와 관련한 항목을 객체 비구조화로 추출
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // index.html 페이지에 추가한 <script>에 의해서 설정
    const { naver } = window;

    // 네이버 개발자 사이트에 등록한 애플리케이션의 ID와 Callback URL을 상수로 정의
    const NAVER_CLIENT_ID = `5chnMhfd1oStUPJr9rqa`;
    const NAVER_CALLBACK_URL = `http://localhost:3000/login`;

    // 네이버 로그인에 필요한 #1 값 설정, #2 초기화, 
    // #3 로그인 결과를 반환하는 콜백 함수를 등록해 주는 함수
    const initializeNaverLogin = () => {
        // #1
        const naverLogin = new naver.LoginWithNaverId({
            clientId: NAVER_CLIENT_ID, 
            callbackUrl: NAVER_CALLBACK_URL, 
            isPopup: true, 
            loginButton: { color: 'green', type: 3, height: 60 }
        });

        // #2
        naverLogin.init();
    
        // #3
        naverLogin.getLoginStatus(function (status) {
            // 로그인 성공 시 true를 값으로 가짐
            if (status) {
                // 로그인 성공 시 naverLogin의 user 객체에 있는 정보 중 
                // 필요한 정보를 로컬 스토리지에 저장
                localStorage.setItem('userName', naverLogin.user.name);
                localStorage.setItem('userNickname', naverLogin.user.nickname);
                localStorage.setItem('userPhoto', naverLogin.user.profile_image);
            
                // 부모 브라우저 창의 주소를 홈(/)으로 변경 후 
                // 팝업 브라우저 창을 닫음
                window.opener.location.href = "/";
                window.close();
            } 
        });
    };    

    // 최초 마운트 시 initializeNaverLogin 함수를 호출
    useEffect(() => {
        initializeNaverLogin();
    }, []);

    // 로그인 버튼을 출력(id는 고정된 값)
    return <div id="naverIdLogin" />;
};

export default NaverLogin;

 

로그인 컴포넌트 추가

Login.js 파일을 생성하고, 아래 코드를 추가합니다. 해당 컴포넌트에서는 네이버 로그인을 비롯한 다양한 소셜 로그인과 ID, PW 기반 로그인을 쉽게 추가할 수 있도록 랩핑해 주는 역할을 합니다.

import NaverLogin from "./NaverLogin";
import { useEffect } from "react";

const Login = () => {

    useEffect(() => {
        // 로컬 스토리지에 userName이 존재하는 경우 로그인한 것으로 판단
        // 이미 로그인한 경우 홈(/)으로 이동
        const isLogin = !!window.localStorage.getItem('userName');
        if (isLogin) {
            window.location.href = '/';
        }
    }, []);

    return (
        <>
            <div style={{ textAlign: 'center', padding: '30px' }}>
                {/* 다양한 방식의 로그인 컴포넌트를 추가 */}
                <NaverLogin />
            </div>
        </>
    );
};

export default Login;

 

로그인/로그아웃 버튼 추가

로그인 여부에 따라 로그인/로그아웃 버튼을 제공하도록 App.js 파일을 수정합니다.

import './App.css';
import { Route } from 'react-router-dom';
import BoardList from "./board/BoardList";
import BoardDetail from "./board/BoardDetail";
import BoardWrite from './board/BoardWrite';
import Login from './Login';

const App = () => {
  // 로그인 페이지로 이동
  const handlerLogin = (e) => {
    e.preventDefault();
    window.location.href = '/login';
  };

  // 로그아웃 처리 
  // 로컬 스토리지 내용 삭제 후 홈(/)으로 이동
  const handlerLogout = (e) => {
    e.preventDefault();
    localStorage.clear();
    window.location.href = '/';
  };

  // 로그인 페이지가 아닌 경우 로그인/로그아웃 버튼을 제공
  // 로그인 상태인 경우 로그인 정보와 로그아웃 버튼을 
  // 로그아웃 상태인 경우 로그인 버튼을 제공
  const isNotLoginPage = window.location.pathname === '/login' ? false : true;
  const isLogin = !!window.localStorage.getItem('userName');
  
  return (
    <>
      <div style={{ textAlign: 'right', padding: '30px' }}>
        { isNotLoginPage && isLogin && 
          <> 
            { window.localStorage.getItem('userName') }님 환영합니다.
            &nbsp;
            <button onClick={handlerLogout}>Logout</button>
          </> 
        }
        { isNotLoginPage && !isLogin && 
          <>
            <button onClick={handlerLogin}>Login</button>
          </>
        }        
      </div>

      <Route path="/" component={BoardList} exact={true} />
      <Route path="/login" component={Login} exact={true} />
      <Route path="/board" component={BoardList} exact={true} />
      <Route path="/board/write" component={BoardWrite} />
      <Route path="/board/detail/:boardIdx" component={BoardDetail} />
    </>
  );
};

export default App;

 

실행 결과

로그아웃 상태인 경우 Login 버튼을 제공합니다.

 

로그인 버튼을 클릭하면 로그인 기능을 제공하는 화면(/login)으로 이동합니다.

 

로그인에 성공하면 사용자 정보와 함께 Logout 버튼을 제공합니다.

 

최종 코드

board-react_naver.zip
1.11MB

728x90
반응형

댓글