소셜로그인 연동 → 네이버 2

로그인 성공 페이지

  • 로그인 성공 후 Redirect 된 url에서 토큰 값 받기
    • 토큰으로 사용자의 정보 가져옴

토큰 값 가져오기

로그인 성공 후 Redirect 된 url에 # (hash)로 access_token 값을 주고 있음.

1
2
3
4
5
const getNaverToken = async () => {
    if(!location.hash) return;
    const token = location.hash.split('=')[1].split('&')[0];
    console.log(token);
}

토큰 값 받기 완료.

사용자 정보 가져오기

네이버 API를 사용해서 사용자의 정보를 받을 수 있음. → 참고 블로그
내가 못찾는건지 모르겠지만,, 개발 가이드 찾는게 조금 어려웠음 ㅜㅜ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try {
    const response = await fetch('https://openapi.naver.com/v1/nid/me', {
        method: 'GET',
        headers: {
            Authorization: `Bearer ${token}`
        },
    })

    const naverUser = await response.json();
    const username = naverUser.response.name
    setUsername(username);
    setLoading(false);
} catch (err) {
    console.error(err);
    setError('Error fetching user data');
    setLoading(false);
}

fetch에서 계속 오류가 떴다. fetch 할 수 없다…?

fetch 할 수 없는 이유

원래는 token의 문제가 1순위 이겠지만, 콘솔에도 토큰이 잘 나오고 있어서 생각해보기에 CORS 오류이지 않을까 생각.
그래서 프록시 서버를 설정하는 방법을 찾아봄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// vite.config.js
export default defineConfig({
    // ...
    
    server: {
        proxy: {
            '/api/naver': {
                  target: 'https://openapi.naver.com',
                  changeOrigin: true,
                  rewrite: (path) => path.replace(/^\/api\/naver/, '')
            }
        }
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
try {
    const response = await fetch('/api/naver/v1/nid/me', {
        method: 'GET',
        headers: {
            Authorization: `Bearer ${token}`
        },
    })

    // ...
}
catch(e) {
    console.error(e);
}

vite.confing.js 에서 server에 proxy 를 설정해주고 ‘/api/naver/v1/nid/me’ 호출해주니까 값이 잘 넘어옴.

성공!

SuccessLoing.jsx 에 카카오, 네이버 둘다 설정을 해주다보니까 코드가 지저분해져서 정리를 다시 하였음.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// SucessLoing.jsx
const getKakaoToken = async () => {
    try {
        // 카카오 API를 사용하여 액세스 토큰 요청
        const response = await fetch('https://kauth.kakao.com/oauth/token', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: new URLSearchParams({
                grant_type: 'authorization_code',
                client_id: 'REST_API_KEY',
                redirect_uri: REDIRECT_URI,
                code: code,
            }),
        });

        const data = await response.json();
        const accessToken = data.access_token;

        // 액세스 토큰을 사용하여 사용자 정보 요청
        const userResponse = await fetch('https://kapi.kakao.com/v2/user/me', {
            headers: {
                Authorization: `Bearer ${accessToken}`,
                'Content-type': 'application/x-www-form-urlencoded;charset=utf-8',
            },
        });

        const userData = await userResponse.json();
        const username = userData.kakao_account.profile.nickname;

        setUsername(username);
        setLoading(false);
    } catch (err) {
        console.error(err);
        setError('Error fetching user data');
        setLoading(false);
    }
};

const getNaverToken = async () => {
    if(!location.hash) return;
    // 액세서 토큰 추출
    const token = location.hash.split('=')[1].split('&')[0];
    console.log(token);

    try {
        // 네이버 API를 사용하여 사용자 정보 요청
        const response = await fetch('/api/naver/v1/nid/me', {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${token}`
            },
        })

        const naverUser = await response.json();
        const username = naverUser.response.name
        setUsername(username);
        setLoading(false);
    } catch (err) {
        console.error(err);
        setError('Error fetching user data');
        setLoading(false);
    }
}

useEffect(() => {
    if (code) {
        getKakaoToken();
    } else {
        getNaverToken();
    }
}, [code]);

if (loading) {
    return <CenteredMessage message="Loading..." />;
}

if (error) {
    return <CenteredMessage message={error} />;
}

return(
    <>
    <div style=>
        <strong>{code ? '카카오' : '네이버'} 로그인 성공</strong>
        <p><strong>{username}</strong>님 반갑습니다.</p>
    </div>
    {code
        ? <Button
            onClick={() => nav('/')}
            type={'func'}
            text={'메인으로 가기'}
          />
        : ''
    }
    </>
)


// SuccessLogin 함수 밖에
const CenteredMessage = ({ message }) => (
    <div style=>
        <p>{message}</p>
    </div>
);

평가

역시 한번에 손쉽게 될 리가 없다. 🤣🤣🤣
글로 쓰려니 뭔가 짧고 쉬워보이지만, API 발급을 하고 연동을 하는 것부터 로그인 정보를 가져오는 것 까지…
그래도 역시 해내니까 뿌듯하고 재미있다.
천천히 구글이나 페이스북 등 다양한 소셜로그인 연동을 해봐야겠다.

참고 블로그 - 네이버 로그인 개발가이드
참고 블로그 - 리액트로 네이버 소셜 로그인 적용하기
참고 블로그 - React 네아로
참고 블로그 - 로그인 상태 확인하여, 사용자 정보 가져오기