먼저 터미널에 npm i passport passport-local passport-kakao bcrypt
를 입력해 4개의 모듈을 설치해줍니다. (docker alpine 사용시 bcrypt 모듈을 사용 할 수 없기에 bcryptjs 또는 다른 해결책 방법을 사용해야한다.)
모듈을 설치했으니 app.js에서 모듈을 선언해주어야합니다.
var createError = require('http-errors');
var sequelize = require('./models').sequelize;
var express = require('express');
const session = require('express-session');
const passport = require('passport'); //추가
const passportConfig = require('./passport'); //추가
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
require('dotenv').config();
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
const authRouter = require('./routes/auth'); //추가 (뒤에서 사용할예정)
var app = express();
sequelize.sync();
passportConfig(passport);
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
}));
app.use(passport.initialize()); //추가
app.use(passport.session()); //추가 (req.session 객체는 express-session에서 생성하는 것이므로 passport 미들웨어는 express-session 미들웨어보다 뒤에 연결해야 합니다.)
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/auth', authRouter); //추가 (뒤에서 사용할예정)
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
먼저 새로 passport 파일을 생성한 후 index.js, kakaoStrategy.js 파일을 생성합니다.
passport/index.js
const kakao = require('./kakaoStrategy');
const {User} =require('../models');
module.exports = (passport) => {
passport.serializeUser((user, done) =>{ //req.session 객체에 어떤 데이터를 저장할지 선택. 매개변수로 user를 받아서 done 함수에 두번째 인자로 user.id 를 넘기고 있다.(=세션에 사용자 id저장) done함수의 첫번째 인자는 에러 발생시 사용
done(null, user.id);
});
passport.deserializeUser((id,done) => { // 매요청시 실행된다. passport.session() 미들웨어가 이 메서드를 호출한다. serializeUser에서 세션에 저장했던 id를 받아 데이터베이스에서 사용자 정보를 조회한다. 조회한 정보를 req.user에 저장하므로 앞으로 req.user를 통해 로그인한 사용자의 정보를 가져올 수 있다.
User.findOne({
where: {id}})
.then(user=> done(null, user))
.catch(err => done(err));
});
kakao(passport);
}
passport/kakaoStrategy
const KakaoStrategy = require('passport-kakao').Strategy;
const {User} = require('../models');
module.exports = (passport) => {
passport.use(new KakaoStrategy({
clientID:process.env.KAKAO_ID, //kakao에서 발급해주는 id, .env 파일 생성후 KAKAO_ID:카카오에서 발급해준 api 를 추가해주면 된다.
callbackURL:'/auth/kakao/callback', //인증결과를 받는 라우터이다.
}, async (accessToken, refreshToken, profile, done)=> {
try {
const exUser = await User.findOne({ //가입이력 확인
where: {
snsId: profile.id,
provider: 'kakao'
}});
if (exUser) {
done(null, exUser);
} else {
const newUser = await User.create({ //새 유저 생성
email: profile._json?.kakao_account_email,//nullish라 판단하면 에러가 아닌 undefined 출력
nick_name: profile.displayName,
snsId: profile.id,
rank:"common",
provider: 'kakao',
});
done(null, newUser);
}
}catch (error) {
console.error(error);
done(error);
}
}));
};
카카오 로그인 라우터 즉 어떤 라우터로 요청을 주고받는지 설정할 차례이다.
routes 폴더안에 auth.js파일을 생성하자
const express = require('express');
const passport = require('passport');
const bcrypt = require('bcryptjs'); //현재 docker alpine으로 서버를 구동중이라 bcrypt대신 bcryptjs모듈을 사용한다.
const { isLoggedIn, isNotLoggedIn } = require('./middlewares');
const { User } = require('../models');
const router = express.Router();
/*
router.get('/logout', isLoggedIn, (req,res) => // passport 버전이 업글되면서 문법이 바뀌었다.
req.logout(function(err) {
req.session.destroy();
if (err) { return next(err); }
res.redirect('/');
})); // 뒤에 로그아웃 구현
*/
router.get('/kakao', passport.authenticate('kakao')); // get /auth/kakao 로 접근하면 카카오 로그인 창으로 연결된다.
router.get('/kakao/callback',passport.authenticate('kakao',{ // 로그인에대한 결과를 GET /auth/kakao/callback 로 받는다.
failureRedirect: '/',
}),(req,res)=> {
res.redirect('/');
});
module.exports = router;
이렇게하면 카카오 로그인구현은 끝이났다.
카카오로그인 실습을 위해 카카오 플렛폼 만들기접속 후 애플리케이션 추가하기버튼을 누른다.
앱 이름과 사업자명을 설정하면 된다.
아까 만들어놓은 .env파일에 KAKAO_ID:REST API키를 입력한다.
앱설정에서 플랫폼으로 들어가서 web플렛폼을 등록하고 아래 Redirect URL을 등록한다.
Client Secret 을 사용하는 경우 제품설정> 카카오 로그인 > 보안 에서 on 으로 설정을 하고 코드에 해당하는 부분을 .env에 넣고 사용하면 된다.
위 설정을 한 후 서버를 실행시켜보면 카카오 로그인이 되는 것을 볼 수 있다.