const express = require("express");
const router = express.Router();
const cors = require("cors");
const passport = require("passport");
const KakaoStrategy = require("passport-kakao").Strategy;
const models = require("../models");
const { isLoggedIn, isNotLoggedIn } = require("../middlwares/auth");
const path = require("path");
require("dotenv").config();
router.use(passport.initialize());
router.use(passport.session());
passport.serializeUser((user, done) => { // -----------------------(3)
console.log("serializeUser :: ", user);
done(null, user.snsId); // 세션에 사용자 정보인 id를 저장
});
passport.deserializeUser(async (snsId, done) => {
// 세션에 저장되어 있는 id를 인자 값으로 전달받음
console.log("deserializeUser :: ", snsId);
try {
const user = await models.Users.findOne({
where: {
snsId: snsId,
},
raw: true,
});
done(null, user); // req.user 객체 생성
} catch {
done(null, false, {
message: "서버에 문제가 발생했습니다. 잠시 후 다시 시도해 주세요.",
});
}
});passport.use( // ---------------------------------------------(2)
"kakao",
new KakaoStrategy(
{
clientID: process.env.clientID,
clientSecret: process.env.clientSecret,
callbackURL: process.env.callbackURL
},
async (accessToken, refreshToken, profile, done) => {
console.log("kakao profile", profile);
try {
const exUser = await models.Users.findOne({
where: { snsId: profile.id, provider: "kakao" },
});
if (exUser) {
done(null, exUser);
} else {
const newUser = await models.Users.create({
email: profile._json && profile._json.kakao_account_email,
snsId: profile.id,
provider: "kakao",
});
done(null, newUser);
}
} catch (error) {
console.error(error);
done(error);
}
}
)
);
router.get("/", (req, res, next) => { // -----------------------(1)
passport.authenticate("kakao", (authError, user, info) => {
if (authError) {
console.error(authError);
return next(authError);
}
if (!user) {
return res.redirect(`/?loginError=${info.message}`);
}
return req.login(user, (loginError) => {
if (loginError) {
console.error(loginError);
return next(loginError);
}
return res.redirect("<http://localhost:3000/>");
});
})(req, res, next); // 미들웨어 내의 미들웨어에는 (req, res, next)를 붙입니다.
});
router.get( // --------------------------------------------(4)
"/callback",
passport.authenticate("kakao", {
failureRedirect: "<http://localhost:3000/user/login>",
}),
(req, res) => {
res.redirect("<http://localhost:3000>");
}
);
module.exports = router;
- 필요한 라이브러리를 가져와서 임포트 시킨다. 아래와 같은 코드는 필수적이다. 다른 임포트된 코드들은 앞의 passport에 정리해놨다.
const passport = require("passport");
const KakaoStrategy = require("passport-kakao").Strategy;
const models = require("../models");
2. https://developers.kakao.com/product/kakaoLogin(카카오 홈페이지) 들어간다. 내 애플리케이션에서 나만이 사용할 것이기에 기본 정보를 등록한다. 그리고 나면 맨 첫 화면에 rest api가 나온다. 이를 따로 저장해놓는다. 나중에 잃어버렸을 때를 대비하여, 앱 키에서 재발급받는다.

내 애플리케이션 > 앱 설정 > 플랫폼에 들어가서 web에 내 사이트 도메인을 등록해야 한다.

위와 같이 등록하고 나서 밑부분에 redirect uri를 등록하라고 나와 있다. 위를 위해 등록한다.


들어가 보면 활성화 설정이 나오는데 카카오톡 서비스를 이용할 수 있도록 먼저 켜놓고, redirect uri를 설정해놓는다. 내 경우에는 프론트에서 백엔드로 넘겨주기 때문에 백엔드 사이트를 등록해놓았다.
그리고, 내 애플리케이션 > 제품 설정 > 카카오 로그인 > 보안 을 들어가보면 client secret을 발급 받고 활성화시켜 놓는다.
체크해야 하는 부분
- clientID : 내 애플리케이션 > 앱 설정 > 요약 정보
- clientSecret : 내 애플리케이션 > 제품 설정 > 카카오 로그인 > 보안
- redirectUri : 내 애플리케이션 > 제품 설정 > 카카오 로그인
- 위의 코드에 표시된 (1)-(2)-(3)-(4) 순서대로 흐름이 된다. 카카오톡 로그인 버튼을 누르면 (1)이 실행되게 된다. passport.authenticate로 가게 된다. 이는 (2)번의 passport.use("kakao",new KakaoStrategy())를 의미한다. 이 말은 kakaoStrategy의 전략을 실행하겠다는 말이다. 여기에는 카카오 서버에서 보낸 카카오 계정 정보가 있다.→ 위 코드는 db에 설정한 snsid와 provider가 있는지 확인한다.
- 이는 카카오톡 로그인을 위하여 만든 컬럼이다. 두 개의 컬럼이 존재한다면 카카오톡으로 가입한 적이 있다는 말이다.deserializeUser는 passport.session 미들웨어가 이 메서도를 호출한다. 세션에 저장했던 아이디를 받아 데이터베이스에서 사용자 정보를 조회한다. 조회한 정보를 req.user에 저장한다. req.user를 통해 로그인한 사용자의 정보 가져올 수 있다. 세션에 저장한 아이디 통해 사용자 정보 객체 불러온다.
- 그리고 if문으로 넘어가는데 user가 있다면 passport.serializeUser로 들어와진다. 클라이언트에 세션을 보내게 된다. 여기서 snsId만 보내게 된다.
- const exUser = await models.Users.findOne({ where: { snsId: profile.id, provider: "kakao" }, });
- 설정하면서 라우터 / 부분에서 user가 없으면 나는 오류가 있다.이 오류가 많이 나게 된다. 이 부분은 프론트에서 백엔드로 넘겨줄 때 id와 password를 받아올 때 passport에서 전달을 못 받아서 나는 에러이다. 그래서 코드 중간 중간에 콘솔에 로그를 찍어서 잘 받아와지는지 확인해야 한다. 또한 변수명이 달라서 못 받아오는 경우도 있으니까 확인해야 한다. 구글링해서 보니까 (req,res)로 미들웨어를 이 순서대로 받아와야 하는데 순서를 다르게 해서 못 받아오는 경우도 존재하였다.
- 여기서 확인할 것은 프론트와 백엔드의 변수명이 일치하는지
- 백엔드와 db의 저장한 id와 password 변수명이 일치하는지
- { message : 'Missing credentials' }
- (4)에 보면 로그인하고 콜백으로 하여 라우터를 반환해준다. 이는 페이지이동을 해주기 위함인데 내 경우는 코드에 res.redirect로 해서 페이지이동을 하였다.
아래와 같은 사이트를 참고하였습니다.
https://velog.io/@new_wisdom/Node.js-10-Passport로-소셜-로그인-구현하기
const express = require("express");
const router = express.Router();
const cors = require("cors");
const passport = require("passport");
const KakaoStrategy = require("passport-kakao").Strategy;
const models = require("../models");
const { isLoggedIn, isNotLoggedIn } = require("../middlwares/auth");
const path = require("path");
require("dotenv").config();
router.use(passport.initialize());
router.use(passport.session());
passport.serializeUser((user, done) => { // -----------------------(3)
console.log("serializeUser :: ", user);
done(null, user.snsId); // 세션에 사용자 정보인 id를 저장
});
passport.deserializeUser(async (snsId, done) => {
// 세션에 저장되어 있는 id를 인자 값으로 전달받음
console.log("deserializeUser :: ", snsId);
try {
const user = await models.Users.findOne({
where: {
snsId: snsId,
},
raw: true,
});
done(null, user); // req.user 객체 생성
} catch {
done(null, false, {
message: "서버에 문제가 발생했습니다. 잠시 후 다시 시도해 주세요.",
});
}
});passport.use( // ---------------------------------------------(2)
"kakao",
new KakaoStrategy(
{
clientID: process.env.clientID,
clientSecret: process.env.clientSecret,
callbackURL: process.env.callbackURL
},
async (accessToken, refreshToken, profile, done) => {
console.log("kakao profile", profile);
try {
const exUser = await models.Users.findOne({
where: { snsId: profile.id, provider: "kakao" },
});
if (exUser) {
done(null, exUser);
} else {
const newUser = await models.Users.create({
email: profile._json && profile._json.kakao_account_email,
snsId: profile.id,
provider: "kakao",
});
done(null, newUser);
}
} catch (error) {
console.error(error);
done(error);
}
}
)
);
router.get("/", (req, res, next) => { // -----------------------(1)
passport.authenticate("kakao", (authError, user, info) => {
if (authError) {
console.error(authError);
return next(authError);
}
if (!user) {
return res.redirect(`/?loginError=${info.message}`);
}
return req.login(user, (loginError) => {
if (loginError) {
console.error(loginError);
return next(loginError);
}
return res.redirect("<http://localhost:3000/>");
});
})(req, res, next); // 미들웨어 내의 미들웨어에는 (req, res, next)를 붙입니다.
});
router.get( // --------------------------------------------(4)
"/callback",
passport.authenticate("kakao", {
failureRedirect: "<http://localhost:3000/user/login>",
}),
(req, res) => {
res.redirect("<http://localhost:3000>");
}
);
module.exports = router;
- 필요한 라이브러리를 가져와서 임포트 시킨다. 아래와 같은 코드는 필수적이다. 다른 임포트된 코드들은 앞의 passport에 정리해놨다.
const passport = require("passport");
const KakaoStrategy = require("passport-kakao").Strategy;
const models = require("../models");
2. https://developers.kakao.com/product/kakaoLogin(카카오 홈페이지) 들어간다. 내 애플리케이션에서 나만이 사용할 것이기에 기본 정보를 등록한다. 그리고 나면 맨 첫 화면에 rest api가 나온다. 이를 따로 저장해놓는다. 나중에 잃어버렸을 때를 대비하여, 앱 키에서 재발급받는다.

내 애플리케이션 > 앱 설정 > 플랫폼에 들어가서 web에 내 사이트 도메인을 등록해야 한다.

위와 같이 등록하고 나서 밑부분에 redirect uri를 등록하라고 나와 있다. 위를 위해 등록한다.


들어가 보면 활성화 설정이 나오는데 카카오톡 서비스를 이용할 수 있도록 먼저 켜놓고, redirect uri를 설정해놓는다. 내 경우에는 프론트에서 백엔드로 넘겨주기 때문에 백엔드 사이트를 등록해놓았다.
그리고, 내 애플리케이션 > 제품 설정 > 카카오 로그인 > 보안 을 들어가보면 client secret을 발급 받고 활성화시켜 놓는다.
체크해야 하는 부분
- clientID : 내 애플리케이션 > 앱 설정 > 요약 정보
- clientSecret : 내 애플리케이션 > 제품 설정 > 카카오 로그인 > 보안
- redirectUri : 내 애플리케이션 > 제품 설정 > 카카오 로그인
- 위의 코드에 표시된 (1)-(2)-(3)-(4) 순서대로 흐름이 된다. 카카오톡 로그인 버튼을 누르면 (1)이 실행되게 된다. passport.authenticate로 가게 된다. 이는 (2)번의 passport.use("kakao",new KakaoStrategy())를 의미한다. 이 말은 kakaoStrategy의 전략을 실행하겠다는 말이다. 여기에는 카카오 서버에서 보낸 카카오 계정 정보가 있다.→ 위 코드는 db에 설정한 snsid와 provider가 있는지 확인한다.
- 이는 카카오톡 로그인을 위하여 만든 컬럼이다. 두 개의 컬럼이 존재한다면 카카오톡으로 가입한 적이 있다는 말이다.deserializeUser는 passport.session 미들웨어가 이 메서도를 호출한다. 세션에 저장했던 아이디를 받아 데이터베이스에서 사용자 정보를 조회한다. 조회한 정보를 req.user에 저장한다. req.user를 통해 로그인한 사용자의 정보 가져올 수 있다. 세션에 저장한 아이디 통해 사용자 정보 객체 불러온다.
- 그리고 if문으로 넘어가는데 user가 있다면 passport.serializeUser로 들어와진다. 클라이언트에 세션을 보내게 된다. 여기서 snsId만 보내게 된다.
- const exUser = await models.Users.findOne({ where: { snsId: profile.id, provider: "kakao" }, });
- 설정하면서 라우터 / 부분에서 user가 없으면 나는 오류가 있다.이 오류가 많이 나게 된다. 이 부분은 프론트에서 백엔드로 넘겨줄 때 id와 password를 받아올 때 passport에서 전달을 못 받아서 나는 에러이다. 그래서 코드 중간 중간에 콘솔에 로그를 찍어서 잘 받아와지는지 확인해야 한다. 또한 변수명이 달라서 못 받아오는 경우도 있으니까 확인해야 한다. 구글링해서 보니까 (req,res)로 미들웨어를 이 순서대로 받아와야 하는데 순서를 다르게 해서 못 받아오는 경우도 존재하였다.
- 여기서 확인할 것은 프론트와 백엔드의 변수명이 일치하는지
- 백엔드와 db의 저장한 id와 password 변수명이 일치하는지
- { message : 'Missing credentials' }
- (4)에 보면 로그인하고 콜백으로 하여 라우터를 반환해준다. 이는 페이지이동을 해주기 위함인데 내 경우는 코드에 res.redirect로 해서 페이지이동을 하였다.
아래와 같은 사이트를 참고하였습니다.
https://velog.io/@new_wisdom/Node.js-10-Passport로-소셜-로그인-구현하기