본문 바로가기
SPA/Next

[Next] 네이버 로그인 구현하기

by J4J 2022. 3. 1.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 네이버 로그인 구현하는 방법에 대해 적어보는 시간을 가져보려고 합니다.

 

 

 

들어가기에 앞서

 

동일한 방식의 다른 로그인도 구현해보고 싶은 분들은 다음 글들을 참고하시면 좋을 것 같습니다.

 

[Next] 카카오 로그인 구현하기

[Next] 구글 로그인 구현하기

 

 

 

spring과 함께 로그인을 구현하는 방법에 대해 궁금하신 분들은 다음 글을 참고하시면 좋을 것 같습니다.

 

[Next] Naver 로그인 Spring을 활용하여 구현하기

 

 

반응형

 

 

네이버 로그인 구현 방법

 

[ 1. 네이버 디펠로퍼 사이트 로그인 ]

 

Naver Developers에 접속하여 로그인해주시면 됩니다.

 

 

 

[ 2. 내 애플리케이션 등록하기 ]

 

상단 메뉴에서 "Application → 애플리케이션 등록" 을 다음과 같이 확인할 수 있습니다.

 

애플리케이션 등록

 

 

 

애플리케이션 등록을 누르면 등록할 애플리케이션 정보를 입력해줘야 합니다.

 

먼저 다음과 같이 애플리케이션 이름에는 원하는 이름을 입력해주시고 사용 API에는 네이버 로그인을 선택하신 뒤 제공받고자 하는 정보들을 선택해주시면 됩니다.

 

애플리케이션 정보 등록 - 1

 

 

 

스크롤을 해주시면 서비스 환경 설정을 해줘야 합니다.

 

PC에서 사용할지, 모바일에서 사용할지 등에 대한 정보들을 선택해서 URL들을 입력해줄 수 있는 항목입니다.

 

저는 PC에서 테스트를 진행하기 때문에 다음과 같이 PC 웹을 선택해줬고 사용되는 서비스 URL과 Callback URL을 입력해줬습니다.

 

애플리케이션 정보 등록 - 2

 

 

 

여기서 Callback URL의 용도는 네이버 로그인 창을 오픈시킨 뒤 사용자가 네이버 계정을 입력하여 로그인이 이루어질 경우 로그인과 관련된 정보들을 전달받을 URL입니다.

 

저는 index 페이지가 로그인을 하는 페이지이자 Callback 처리도 이루어질 페이지이기 때문에 서비스 URL과 동일하게 입력을 했습니다.

 

모든 내용을 입력했다면 등록하기 버튼을 눌러주시면 애플리케이션 등록이 완료됩니다.

 

 

 

 

[ 3. Client ID 확인 ]

 

등록이 완료되었다면 다음과 같은 화면을 확인할 수 있습니다.

 

애플리케이션 정보

 

 

 

여기 보이는 ClientID와 Client Secret은 코드 구현을 할 때 사용되기 때문에 한번 확인을 하고 넘어가도록 하겠습니다.

 

 

 

[ 4. 로그인 화면 구현 ]

 

먼저 _app.tsx 파일에서는 Naver 로그인을 위한 script 등록을 위해 다음과 같이 수정하겠습니다.

 

import * as React from 'react';
import { AppProps } from 'next/app';
import Head from 'next/head';

const App = ({ Component, pageProps }: AppProps) => {
    return (
        <>
            <Head>
                <script src="https://static.nid.naver.com/js/naveridlogin_js_sdk_2.0.2.js"></script>
            </Head>

            <Component {...pageProps} />
        </>
    )
};

export default App;

 

 

 

다음으로 index.tsx 파일에는 Naver 로그인을 위한 코드를 구현하기 위해 다음과 같이 수정하겠습니다.

 

import * as React from 'react';
import { NextPage } from 'next';
import styled from 'styled-components';
import Router from 'next/router';

const Index: NextPage = () => {

    React.useEffect(() => {
        const naver = (window as any).naver;
        let naverLogin: any;

        const login = () => {
            naverLogin = new naver.LoginWithNaverId({
                clientId: 'asdf12345', // ClientID
                callbackUrl: 'http://localhost:8088', // Callback URL
                isPopup: false, // 팝업 형태로 인증 여부
                loginButton: { 
                    color: 'green', // 색상
                    type: 3, // 버튼 크기
                    height: '60' // 버튼 높이
                }, // 로그인 버튼 설정
            })
    
            naverLogin.init();
        }

        const getToken = () => {
            const hash = Router.asPath.split('#')[1]; // 네이버 로그인을 통해 전달받은 hash 값
            if(hash) {
                const token = hash.split('=')[1].split('&')[0]; // token값 확인
                naverLogin.getLoginStatus((status: any) => {
                    if(status) { // 로그인 상태 값이 있을 경우
                        console.log(naverLogin.user); // 사용자 정보 조회

                        if(!naverLogin.user.getAge()) { // 나이정보 제공을 동의하지 않았을 경우
                            alert('나이 정보는 필수입니다.');
                            naverLogin.reprompt(); // 정보제공창 다시 보여주기

                            return;
                        }

                        // /naver 페이지로 token값과 함께 전달 (서비스할 땐 token 전달을 하지 않고 상태 관리를 사용하는 것이 바람직할 것으로 보임)
                        Router.push({
                            pathname: '/naver',
                            query: {
                                token: token,
                            }
                        })
                    }
                });
            }
        }

        login();
        getToken();
    }, []);

    return (
        <Wrapper>
            <Header.Container>
                <Header.Title>로그인할 방법을 선택해주세요.</Header.Title>
            </Header.Container>

            <Button.Container>
                <Button.ButtonList>
                    <Button.NaverButton id='naverIdLogin' />
                </Button.ButtonList>
            </Button.Container>
        </Wrapper>
    )
}

export default Index;

const Wrapper = styled.div`
    max-width: 720px;

    margin: 0 auto;
`

const Header = {
    Container: styled.div`
        text-align: center;
    `,

    Title: styled.h2``,
}

const Button = {
    Container: styled.div``,

    ButtonList: styled.div`
        display: flex;
        flex-direction: column;
        align-items: center;
    `,

    NaverButton: styled.div``,
}

 

 

 

 

그다음은 /pages 경로에 naver.tsx 파일을 생성한 뒤 로그아웃 코드 구현을 위해 다음과 같이 작성하겠습니다.

 

import { NextPage } from 'next';
import Router, { useRouter } from 'next/router';
import * as React from 'react';
import styled from 'styled-components';
import axios from 'axios';

const Naver: NextPage = () => {

    const router = useRouter();

    const NaverLogout = async () => {
        // 실제 url은 https://nid.naver.com/oauth2.0/token이지만 proxy를 적용하기 위해 도메인은 제거
        const res = await axios.get('/oauth2.0/token', {
            params: {
                grant_type: 'delete',
                client_id: 'asdf12345', // Client ID
                client_secret: 'qwer12345', // Client Secret
                access_token: router.query.token, // 발급된 Token 정보
                service_provider: 'NAVER'
            }
        })

        if(res) {
            Router.push('/'); // 로그인 페이지로 이동
        }
    }

    return (
        <Wrapper>
            <Title>Naver Page...</Title>
            <Button onClick={NaverLogout}>
                <ButtonText>Logout</ButtonText>
            </Button>
        </Wrapper>
    )
}

export default Naver;

const Wrapper = styled.div`
    max-width: 720px;

    margin: 0 auto;

    display: flex;
    flex-direction: column;
    align-items: center;
`;

const Title = styled.h2``;

const Button = styled.button`
    background-color: #19ce60;

    width: 360px;
    height: 40px;

    margin: 6px 0;

    border: none;
    border-radius: 6px;

    cursor: pointer;
`;

const ButtonText = styled.h4`
    margin: 0;
    padding: 0;

    font-size: 18px;
    color: #ffffff;
`;

 

 

 

마지막으로 root 경로에 next.config.js 파일을 생성한 뒤 proxy 설정을 위해 다음과 같이 작성해주시면 됩니다.

 

module.exports = {
    async rewrites() {
        return [
            {
                source: '/oauth2.0/:path*', // url이 source에 해당될 경우
                destination: 'https://nid.naver.com/oauth2.0/:path*', // destination으로 redirect
            },
        ];
    },
}

 

 

 

next.config.js 파일에서 proxy 설정을 해준 이유는 로컬에서 테스트하기 위함입니다.

 

proxy 설정을 해주지 않고 naver.tsx파일에서 axios를 이용해 바로 접근할 경우 CORS 에러가 발생됩니다.

 

proxy 설정을 해주면 CORS가 발생되지 않고 정상적으로 로그아웃 되는 것을 확인할 수 있습니다.

 

 

 

 

테스트

 

서버를 실행시키면 다음과 같은 화면을 확인할 수 있습니다.

 

로그인 화면

 

 

 

네이버 아이디로 로그인 버튼을 누르게 되면 다음과 같이 개인 정보 동의 화면이 나옵니다.

 

개인정보 동의 화면

 

 

 

여기서 만약 연령대를 체크 해제하고 동의하기를 누를 경우 코드에 작성한 대로 나이정보 제공 동의 알림 창이 나오는 것을 확인할 수 있습니다.

 

 

 

 

로그인이 정상적으로 되었다면 다음과 같이 /naver로 이동되어 화면이 나오게 됩니다.

 

로그인 완료 화면

 

 

 

해당 화면에서 Console을 확인하면 로그인한 사용자 정보가 넘어온 것을 확인할 수 있습니다.

 

또한 중요한 사항은 아니지만 babel-polyfill 에러가 발생되는데 쉽게 해결할 수 있는 에러인데 네이버에서 아직도 해결을 안 하고 있다나 뭐라나... 하여튼, 그렇습니다.

 

 

 

마지막으로 여기서 Logout 버튼을 누르게 되면 다시 로그인 창으로 넘어가는 것을 확인할 수 있습니다.

 

로그아웃

 

 

 

 
 

 

 

 

이상으로 네이버 로그인 구현하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글