저번시간까지 해서 user register(join)단계까지 완료했습니다. 이번 시간에는 등록한 user를 login시키는 방법을 알아봅니다.
youtube
*|passport.js
*|app.js
|routers
*|globalRouter
|controllers
*|userController
*|middlewares.js
*|.env
|views
|partials
*|header.pug
join이 성공적으로 이루어지면 바로 사용자를 postLogin 시키기위해 아래와 같이 작성합니다.
globalRouter.post(routes.join, postJoin, postLogin);
import passport from "passsport";
export const postJoin = async (req, res, next) => {
const {body:{name, email, password, password2}} = req;
if(password !== password2){
res.status(400);
res.render("join", {pageTitle: "Join"});
}else{
try{
const user = await User({name, email});
await User.register(user, password);
next();
}catch(e){
console.log(e);
res.render("join", {pageTitle: "Join"});
}
}
};
//body 정보를 postJoin이 넘긴다 생각하고 postLogin은 username과 password를 알아서 찾기 때문에 따로 전달해주지 않아도 되나??
export const postLogin = passport.authenticate('local', {
failureRedirect: routes.login,
successRedirect: routes.home
});
serialize란 어떤 정보를 쿠키에게 포함시킬지를 의미합니다.
위와 같은 형태가 쿠키이구요. 이름이 있고 값이 있죠. 쿠키는 매우 작아야하고 개인정보같은 민감한 정보를 담아선 안됩니다.
deserialize는 쿠키의 정보를 어떻게 실제로 사용할 정보로 전환하는지를 의미합니다. 쿠키로부터 user의 id를 받았다면 id를 통해 실제 user 정보를 가져오는 과정이라고 생각하면 됩니다. deserialize된 유저 정보는 req.user에 담기게 됩니다.
serialize와 deserialize모두 passport-local-mongoose를 plugging하면 추가되는 method로 구현할 수 있습니다.
대부분의 사람들이 위의 과정처럼 쿠키에 id를 보내고 id로 사용자를 식별합니다.
import passport from 'passport';
import User from './models/User';
//passport-local-mongoose가 제공하는 전략(shortcut)
passport.use(User.createStrategy());
//쿠키에 담을 정보에 대한 설정을 passport-local-mongoose가 대신 해줍니다.
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
deserializeuSer(passport.js에서 config 해준)를 통해 user에 대한 정보를 얻어 req.user에 담아주게 됩니다.
import session from 'express-session';
import passport from 'passport';
import './passport';//passport 설정 파일
app.use(session({
secret: process.env.SECRET,
resave: true,
saveUninitialize: false
}));
/*app.use(cookieParser());다음에 적어주어야합니다*/
app.use(passport.initialize());
app.use(passport.session());
이 단계까지는 서버를 재시작 한다음에 로그인이나 회원가입을 테스트 해보려면 꼭 쿠키를 삭제하셔야됩니다. 아니면 오류가 생겨서 정상적인 테스트가 어려울 수 있습니다.
탬플릿에 user에 대한 정보를 전달하기 위해 res.locals.user = req.user || null
로 수정해줍니다.
export const localsMiddleware = (req, res, next) =>{
res.locals.siteName = "Wetube";
res.locals.routes = routes;
//req.user가 없다면 null을 넣는다는 뜻
res.locals.user = req.user || null;
next();
}
user.isAuthenticated를 없앴으므로 코드를 변경해줍니다.
if !user
//login join template
else
//logout upload template
SECRET에 랜덤 문자열 추가해줍니다.(session 옵션으로 사용)
SECRET = "qwfsdgjasdlkfjalsd"
youtube
*|middlewares.js
|routers
*|globalRouter
*|userRouter
*|videoRouter
middlewares에 새로운 middleware onlyPublic을 추가합니다.
로그인한 유저만 접근가능하게 하는 onlyPrivate, 로그인되지 않은 유저만 접근 가능하게 하는 onlyPublic 총 2개의 middleware를 만듭니다.
export const onlyPublic = (req, res, next) => {
//로그인 되어있을 경우
if(req.user){
//home으로 redirect
res.redirect(routes.home);
}else{
//그렇지 않다면 원래 요청에 대한 응답해주기 위해 next()
next();
}
}
exprot const onlyPrivate = (req, res, next) => {
if(!req.user){
res.redirect(routes.home);
}else{
next();
}
}
import {onlyPublic} from '../middlewares';
globalRouter.get(routes.join, onlyPublic, getJoin);
globalRouter.post(routes.join, onlyPublic, postJoin);
globalRouter.get(routes.login, onlyPublic, getLogin);
globalRouter.post(routes.login, onlyPublic, postLogin);
import {onlyPrivate} from '../middlewares';
userRouter.get(routes.editProfile, onlyPrivate, editProfile);
userRouter.get(routes.changePassword, onlyPrivate, changePassword);
userRouter.get(routes.userDetail(), onlyPrivate, userDetail);
videoRouter에서도 editVideo, uploadVideo, deleteVideo에 모두 onlyPrivate middleware를 넣어줍니다.
passport를 사용하면 로그아웃 기능을 손쉽게 구현할 수 있습니다. logout URL에 접근할 때 req.logout()
을 실행해주면 로그아웃이 완료됩니다. 세션 관련 작업도 자동으로 처리해줍니다.
export const logout = (req, res) => {
req.logout();
res.redirect(routes.home);
}