이 노트는 "Nodejs 교과서"를 공부하면서 기록되었다.
Passport는 Node.js에서 사용하는 인증 미들웨어로, 구글, 페이스북, 카카오톡 등 다양한 로그인 기능을 구현할 수 있게해주는 패키지이다!
$ npm i passport passport-local passport-kakao bcrypt
패키지를 설치했다면 passport 폴더를 만들고 index.js를 설치하여 모듈을 만들자!
📃 passport/index.js
const local = require('./localStrategy');
const kakao = require('./kakaoStrategy');
const {User} = require('../models');
module.exports = (passport)=>{
passport.serializeUser((user,done)=>{
done(null,user.id);
});
passport.deserializeUser((id,done)=>{
User.find({where:{id}})
.then(user=>done(null,user))
.catch(err=>done(err))
});
local(passport);
kakao(passport);
}
app.js에서 모듈을 연결한다!
📃 app.js
...
var passport = require('passport');
const passportConfig = require('./passport');
passportConfig(passport);
...
app.use(session({
secret:"#JDKLF439jsdlfsjl",
resave:false,
saveUninitialized:true,
store: sessionStore
}))
app.use(passport.initialize());
app.use(passport.session());
로그인한 사용자는 회원가입과 로그인 라우터에 접근하면 안되고,
로그인 하지 않은 사용자는 로그아웃 라우터에 접근하면 안된다.
🚨 따라서 라우터에 접근 권한을 제어하는 미들웨어가 필요하다! 🚨
📃 routes/middlewares.js
exports.isLoggedIn =(req,res,next)=>{
if(req.isAuthenticated()){
next()
}else{
res.status(403).send('로그인 필요');
}
};
exports.isNotLoggedIn = (req,res,next)=>{
if(!req.isAuthenticated()){
next();
}else{
res.redirect('/')
}
}
passport는 req 객체에 isAuthenticated 메서드를 추가한다.
로그인 중이면 req.isAuthenticated()가 true이고 아니면 false이다.
이 미들웨어를 사용해보자!
📃 routes/page.js
const { isLoggedIn, isNotLoggedIn } = require('./middlewares');
...
router.get('/profile',isLoggedIn, (req,res)=>{
res.render('profile',{title:'내 정보 - NodeBird',user:req.user});
});
router.get('/join',isNotLoggedIn,(req,res)=>{
res.render('join',{
title:"회원가입 - NodeBird",
user:req.user
});
});
📃 routes/auth.js
const express= require('express');
const passport = require('passport');
const bcrypt = require('bcrypt');
const { isNotLoggedIn, isLoggedIn } = require('./middlewares');
const { User } = require('../models');
const router = express.Router();
// 회원 가입
router.post('/join',isNotLoggedIn, async (req,res,next)=>{
const {email,nick,password}=req.body;
try{
const exUser = await User.find({where:{email}});
if(exUser){
console.log('join Error : 이미 가입된 이메일입니다.');
return res.redirect('/join');
}
const hash = await bcrypt.hash(password,12);
await User.create({
email,
nick,
password:hash,
});
return res.redirect('/');
}catch(error){
console.log(error);
return next(error);
}
});
// 로그인
router.post('/login',isNotLoggedIn,(req,res,next)=>{
passport.authenticate('local',(authError,user,info)=>{
if(authError){
console.error(authError);
return next(authError);
}
if(!user){
console.log('login Error');
return res.redirect('/');
}
return req.login(user,(loginError)=>{
if(loginError){
console.error(loginError);
return next(loginError)
}
return res.redirect('/');
});
})(req,res,next); // 미들웨어 내의 미들웨어에는 (req,res,next)를 붙인다.
});
//로그아웃
router.get('/logout',isLoggedIn,(req,res)=>{
req.logout();
req.session.destroy();
res.redirect('/');
})
module.exports =router;
📃 routes/localStrategy.js
const LocalStrategy = require('poassport-local').Strategy;
const bcrypt = require('bcrypt');
const passport = require('passport');
const { User } = require('../models');
module.exports=(passport)=>{
passport.use(new LocalStrategy({
usernameField :'email',
passwordFiled :'password',
}, async(email,password,done)=>{
try{
const exUser = await User.find({where:{email}});
if(exUser){
const result = await bcrypt.compare(password,rxUser,password);
if(result){
done(null,exUser);
} else{
done(null,false,{message:'비밀번호가 일치하지 않습니다.'});
}
} else{
done(null,false,{message:'가입되지 않은 회원입니다.'});
}
} catch(error){
console.error(error);
done(error);
}
}));
};
passport-local 모듈에서 strategy 생성자를 불러와 사용한다.
strategy?
!어떤 로그인 방식을 취하냐!
sns 로그인은 처음 로그인 할 때는 회원가입 처리, 다음 로그인 부터는 로그인 처리를 해주어야 한다.
📃 passport/kakaoStrategy.js
const passport = require('passport');
const { User } = require('../models');
const KakaoStrategy = require('passport-kakao').Strategy;
module.exports=(passport)=>{
passport.use(new KakaoStrategy({
clientID:process.env.KAKAO_ID,
callbackURL:'auth/kakao/callback',
}, async (accessToken,refreshToken,profile,done)=>{
try{
const exUser = await User.find({where:{snsId:profile.id,provider:'kakao'}});
if(exUser){
done(null,exUser);
} else{
const newUser = await User.create({
email:profile._json && profile._json.kaccount_email,
nick:profile.displayName,
snsId:profile.id,
provider:'kakao',
});
done(null,newUser);
}
}catch(error){
console.error(error);
done(error);
}
}));
};
📃 routes/auth.js - 카카오 로그인 라우터
router.get('kakao',passport.authenticate('kakao'));
router.get('/kakao/callback',passport.authenticate('kakao',{
failureRedirect : '/'
}),(req,res)=>{
res.redirect('/');
});
카카오 개발자 사이트에 들어가서 앱 하나 만든다!
https://developers.kakao.com/
그리고 RESTAPI키를 env 파일에 입력해준다!
안녕하세요. 기획자입니다.
노드JS로 회사에서 사이트를 개발하는데 작성하신 소셜로그인 관련 문의사항이 있습니다.
회원가입 시 카카오나 네이버에 로그인이 되어있는 상태라면 다시 해당 ID,PW를 입력하지 않고
자동으로 끌고와 회원가입절차가 진행되지 않는건가요? www.onoffmix.com 이라는 사이트의 경우
그 기능이 되어 있어 개발자에게 요청하니 노드js는 그 기능이 안된다... 라고 하여 답답하네요..