express로 카카오 소셜 로그인 기능을 적용하기!

이지원·2022년 8월 28일
1
post-thumbnail

요즘에는 회원가입,로그인 기능이 있는 앱,웹사이트에서는 웬만해서 SNS 계정으로 로그인하는 것을 볼 수 있습니다.

사실 저도 아주 유용하게 이용하는데요. 귀찮은 회원가입을 내가 입력하지않아도 된다는 점에서 굉장히 편리한 기능인것같습니다.
SNS 소셜 로그인의 동작방식은 아래와 같습니다!

(사진 출처입니다.)
위 출처에서도 프론트 위주의 자세한 설명이 잘적혀있어서 보고 오셔도 좋을것같습니다.
다만 저는 이번 포스팅에서 위 사진과는 조금다른 순서로 작업할것인데,
2번 인증코드 전달과 3번 인증코드 전송 부분입니다.
2번과 3번은 결국 3번에서 클라이언트 측에서 서버측으로 api를 호출해서 인증코드를 넘겨줘야하기때문에,
이부분을 생략하고자 kakao측에서 인증코드 받는 부분을 클라이언트가아닌 서버측으로 바로 넘겨줄것입니다.

이제 실전으로 들어가봅시다!.

kakao 개발자 페이지에서 카카오 로그인 사용등록하기

카카오 개발자 페이지

해당 링크에 들어가서 로그인 한뒤 카카오 로그인 제품을 클릭합니다 들어가서 시작하기를 클릭하시면

애플리케이션 추가하기 버튼이 보입니다.
해당 애플리케이션이란 우리가 카카오 로그인기능을 사용할 우리의 앱,웹사이트를 뜻합니다. 하나 생성해둡시다!

redirect URL 설정

아래 사진과같이 redirectUrl을 설정하는곳이 있습니다.
이부분이 맨위에 sns동작방식에서 2번 인증코드 전달을 받는 url 입니다.
저는 서버측으로 바로 전달받기로 하였으니,백엔드의 api 주소로 설정하였습니다.
(클라이언트측으로 하실분은 프론트엔드에서 받을 url주소로 하셔도 무방합니다)

플랫폼 설정

저는 웹사이트에서 카카오 로그인을 사용할것이기 때문에
클라이언트 주소와 백엔드 주소를 하나씩 등록하였습니다.

카카오에서 key발급받기


여기서 저희는 REST API로만 사용할것이기때문에 REST API키를 이용하겠습니다.

자! 이러면이제 설정은 다 끝났습니다. 이제부터 코딩시작입니다.

코딩시작

클라이언트 코드

우선 클라이언트에서 카카오 로그인 버튼을클릭하면 카카오 계정을 입력할 수 있게 해줘야겠죠.
해당부분은 아래와 같습니다.

아래 함수를 카카오로그인 버튼 부분에 클릭함수로 지정합니다.
environment.RESTAPIKEY 변수는 아까위에서 언급한 RESTAPI key입니다!
이렇게 작성해주면 카카오로그인 버튼 클릭시 카카오계정을 입력하는 카카오창으로 이동할것입니다.

  kakaoLogin() {
      window.location.href = 'https://kauth.kakao.com/oauth/authorize?client_id=' + environment.RESTAPIKEY + '&redirect_uri=' + encodeURIComponent(`localhost:8100/auth/kakao`) + '&response_type=code';
  }

백엔드 코드

인가코드 확인하기

위에서 카카오계정을 입력하여 로그인하면
인가코드가 위에서 설정한 redirectURL로 들어오게됩니다.
url query형식으로 들어오기 때문에 아래와같이 작성해주시면
code에 인가코드가 들어오게됩니다.
이제 인가코드를 받았으니. 해당하는 인가코드로 카카오 측의 토큰을 발급받아야합니다!

app.get('/api/auth/kakao', async (req, res) => {
        const code = req.query.code;
		
}

토큰 발급받기

app.get('/api/auth/kakao', async (req, res) => {
        const code = req.query.code;
        // 토큰발급받기
		const authToken = await Axios.post('https://kauth.kakao.com/oauth/token', {}, {
                headers: {
                    "Content-Type": "application/x-www-form-urlencoded"
                },
                params:{
                    grant_type: 'authorization_code',
                    client_id: CONFIG.KAKAO.RESTAPIKEY,
                    code,
                    redirect_uri: localhost:8100/api/ouath/kakao
                }
            });
}

아래의 요청파라미터를 보시면 위와같이 post콜로 데이터를 실어보내달라고 카카오측에서 말하고있으니 전송해주면됩니다.
client_id: 위에서 발급받은 RESTAPIKEY
code: 인가코드
redirect_uri: 등록한 redirect 주소

요청파라미터

응답데이터

사용자 정보 가져오기

응답데이터에서 받은
access_token으로 사용자 정보를 가져올 수 있습니다!

// Access token을 이용해 정보 가져오기
            const authInfo = await Axios.post('https://kapi.kakao.com/v2/user/me', {}, {
                headers: {
                    "Content-Type": "application/x-www-form-urlencoded",
                    'Authorization': 'Bearer ' + authToken.data.access_token
                }
            });

그러면 authInfo.data를 출력해보시면
아래에서 동의항목을 설정한 사용자의 정보를 얻을 수 있습니다.

회원가입 혹은 로그인

이렇게 되면 마무리가 다 되었는데요, 사용자 정보를 가져온다음 authInfo.data.id를 출력해보시면
특정한 숫자를 볼 수 있는데, 이부분은 카카오측에서 발급해주는 각 사용자를 구분하는 고유값 입니다.
DB에서는 unique key라고 보시면 됩니다.
그래서 저는 이 키를 기준으로 서버측에서 이미 카카오로그인으로 우리회원db에 있는 사용자 인지 판단을 했습니다.

const row = (await db.query(`select * from user where snsPrimaryKey=? and snsType="kakao"`, [authInfo.data.id]))[0];
            if (row) {
                // 회원가입된 유저
                req.session.userId = row.id;
                req.session.save(() => { });
                res.redirect('http://localhost:4100');
                return;
            } 
            //회원가입 페이지로 redirect
res.redirect('http://localhost:4100/auth/signup?token=' + encodeURIComponent(signupToken) + (data.properties && data.properties.nickname ? '&name=' + encodeURIComponent(data.properties.nickname) : ''));
            

저희는 서비스상 카카오로 받아온정보를 미리 입력하고 클라이언트에 회원가입페이지로 이동시켜서 회원가입을 마무리하는 방식으로 진행하여 아래와같이 진행하였으나,
이러한 과정이아닌 카카오로그인 버튼을 클릭하면 바로회원가입 시키고 로그인된 상태로 이동시키고 싶으시다면
해당 함수에서 받아온 사용자 정보로 회원가입을 시키고,로그인까지 시켜준뒤 우리 서버측 (세션,토큰을) url에 실어서 redirect 시킨다음 클라이언트측에서는 (쿠키,storage)에 저장시켜주면 될것입니다.

최종코드

app.get('/api/auth/kakao', async (req, res) => {
        const code = req.query.code;
        try { 
            // Access token 가져오기
            const res1 = await Axios.post('https://kauth.kakao.com/oauth/token', {}, {
                headers: {
                    "Content-Type": "application/x-www-form-urlencoded"
                },
                params:{
                    grant_type: 'authorization_code',
                    client_id: CONFIG.KAKAO.RESTAPIKEY,
                    code,
                    redirect_uri: (CONFIG.PRODUCT ? "https://" : 'http://') + req.headers.host + '/api/auth/kakao'
                }
            });

            // Access token을 이용해 정보 가져오기
            const res2 = await Axios.post('https://kapi.kakao.com/v2/user/me', {}, {
                headers: {
                    "Content-Type": "application/x-www-form-urlencoded",
                    'Authorization': 'Bearer ' + res1.data.access_token
                }
            });
            console.log(res2.data);

            const data = res2.data;
            const row = (await db.query(`select * from user where snsPrimaryKey=? and snsType="kakao"`, [data.id]))[0];
            if (row) {
                // 회원가입된 유저
                req.session.userId = row.id;
                req.session.save(() => { });
                res.redirect('http://localhost:4100');
                return;
            } 
                res.redirect('http://localhost:4100/auth/signup?token=' + (data.properties && data.properties.nickname ? '&name=' + encodeURIComponent(data.properties.nickname) : ''));
            }
        } catch(e) {
            console.log(e);
            res.status(400).end('Sorry, Login Error!');
        }
    }); 

감사합니다.
다음 포스팅에는 애플로그인 방식을 업로드하겠습니다!

profile
안녕하세요 피드백은 언제나환영입니다.

2개의 댓글

comment-user-thumbnail
2022년 9월 26일

마침 제가 이거 하려고 했었는데 딱 올려주셨네요~~ 감사합니당~~

1개의 답글