이번 이커머스 프로젝트의 챌린지 기능인 소셜로그인을 구현해보기로 했다.
카카오 로그인을 구현하기로 했고, Passport 모듈을 사용해보는 것은 처음이라 많이 어려웠다.
참고자료
Passport
https://inpa.tistory.com/485
https://millo-l.github.io/Nodejs-passport-session-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0/
카카오 로그인 로직
https://inpa.tistory.com/entry/NODE-%F0%9F%93%9A-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EB%A1%9C%EA%B7%B8%EC%9D%B8-Passport-%EA%B5%AC%ED%98%84
https://velog.io/@kjhxxxx/Node.js-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0
먼저 passport, passport-kakao 를 설치하자!
npm i passport passport-kakao
카카오 로그인 전략을 구성하자!
const passport = require('passport');
const KakaoStrategy = require('passport-kakao').Strategy;
const bcrypt = require('bcrypt');
const { User } = require('../models');
const dotenv = require('dotenv');
dotenv.config();
module.exports = (app) => {
app.use(passport.initialize());
passport.use(
new KakaoStrategy(
{
clientID: process.env.KAKAO_ID,
callbackURL: 'http://localhost:5000/auth/kakao/callback',
},
async (accessToken, refreshToken, profile, done) => {
try {
const exUser = await User.findOne({
where: { email: profile._json.kakao_account.email },
});
if (exUser) {
done(null, exUser);
} else {
const newUser = await User.create({
email: profile._json.kakao_account.email,
name: `KAKAO${profile.id}`,
nickname: `KAKAO${profile.id}`,
password: await bcrypt.hash('a00000000', 10),
phone: '01000000000',
point: 3000,
});
done(null, newUser);
}
} catch (error) {
console.log(error);
done(error);
}
}
)
);
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
};
accessToken, refreshToken, profile 은 로그인을 성공하고 callback주소로 돌려받는 값들이다.
로그인하고 받는 profile에서 email을 이용하여 이미 내 프로젝트 DB에 가입되어있는 이메일인지 확인하고,
회원가입 한 유저면 그 정보를 반환, 아니라면 회원가입을 바로 진행한다.
Kakao Develope 에서 제공해주는 데이터의 정보가 많지 않으므로,
이름과 닉네임을 KAKAO라는 문자열을 개인 고유 id값에 붙여 저장하였다.
그리고 소셜로그인에 관한 라우터를 작성하자!
const express = require('express');
const router = express.Router();
const passport = require('passport');
const SocialLoginController = require('../controllers/socialLogin.controller');
const socialLoginController = new SocialLoginController();
router.get('/kakao', passport.authenticate('kakao'));
router.get(
'/kakao/callback',
passport.authenticate('kakao', {
failureRedirect: '/',
}),
socialLoginController.socialLogin
);
module.exports = router;
/kakao 주소로 클라이언트에서 요청이 들어오면, 로그인 전략이 수행되고 /kakao/callback 주소로 값들이 넘어온다.
실패 시, 루트로 redirect 시킨다.
성공하면 컨트로러의 socialLogin 함수를 호출한다.
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');
dotenv.config();
class SocialLoginController {
socialLogin = async (req, res) => {
const accessToken = jwt.sign(
{
id: req.user.id,
nickname: req.user.nickname,
},
process.env.COOKIE_SECRET,
{
expiresIn: '1d',
}
);
res.cookie('accessToken', accessToken);
res.redirect('/');
};
}
module.exports = SocialLoginController;
로그인이 성공하면 jwt token을 cookie에 담아 클라이언트에게 전달!