인프런 커뮤니티 질문&답변

임수진님의 프로필 이미지
임수진

작성한 질문수

[리뉴얼] React로 NodeBird SNS 만들기

쿠키관련) 로그아웃이 되지 않음

작성

·

347

0

안녕하세요. 제로초님~! 강의를 잘 듣고 있습니다.

사소한 문제들은 혼자서 해결해 나가고 있는데, 이 부분은 질문을 검색해도 잘 나오지 않아 질문드립니다.

로그아웃 버튼 클릭시 로그아웃이 되지 않고 401 unauthorize 에러가 발생합니다. 미들웨어에서 res.status(401).send('로그인이 필요합니다')로 해놓은 에러 문구는 뜨지 않고, 콘솔에 401 에러가 뜨는데요.

먼저 isLoggedIn의 미들웨어에 문제가 있다고 생각해서, 브라우저 쿠키를 봤더니 아무것도 존재하지 않았어요 ㅠㅠ 그래서 제 생각에는 쿠키 문제인게 아닌가 하고 있습니다.

잘 안되서 깃헙에서 코드를 퍼와서 복붙해놓긴 했는데, 코드를 첨부합니다.

passport) index.js

const passport = require('passport');
const local = require('./local');
const { User } = require('../models');

module.exports = () => {
passport.serializeUser((user, done) => {
// 서버쪽에 [{ id: 1, cookie: 'clhxy' }]
done(null, user.id);
});

passport.deserializeUser(async (id, done) => {
try {
const user = await User.findOne({ where: { id } });
done(null, user); // req.user
} catch (error) {
console.error(error);
done(error);
}
});

local();
};

// 프론트에서 서버로는 cookie만 보내요(clhxy)
// 서버가 쿠키파서, 익스프레스 세션으로 쿠키 검사 후 id: 1 발견
// id: 1이 deserializeUser에 들어감
// req.user로 사용자 정보가 들어감

// 요청 보낼때마다 deserializeUser가 실행됨(db 요청 1번씩 실행)
// 실무에서는 deserializeUser 결과물 캐싱

passport) local.js

const passport = require('passport');
const { Strategy: LocalStrategy } = require('passport-local');
const bcrypt = require('bcrypt');
const { User } = require('../models');

module.exports = () => {
passport.use(
new LocalStrategy(
{
usernameField: 'email',
passwordField: 'password',
},
async (email, password, done) => {
try {
const user = await User.findOne({
where: { email },
});
if (!user) {
return done(null, false, { reason: '존재하지 않는 이메일입니다!' });
}
const result = await bcrypt.compare(password, user.password);
if (result) {
return done(null, user);
}
return done(null, false, { reason: '비밀번호가 틀렸습니다.' });
} catch (error) {
console.error(error);
return done(error);
}
}
)
);
};

routes) user.js

const express = require('express');
const bcrypt = require('bcrypt');
const { User, Post } = require('../models');
const passport = require('passport');
const router = express.Router();
const { isLoggedIn, isNotLoggedIn } = require('./middlewares');

router.get('/', async (req, res, next) => {
// GET /user
try {
if (req.user) {
const fullUserWithoutPassword = await User.findOne({
where: { id: req.user.id },
attributes: {
exclude: ['password'],
},
include: [
{
model: Post,
attributes: ['id'],
},
{
model: User,
as: 'Followings',
attributes: ['id'],
},
{
model: User,
as: 'Followers',
attributes: ['id'],
},
],
});
res.status(200).json(fullUserWithoutPassword);
} else {
res.status(200).json(null);
}
} catch (error) {
console.error(error);
next(error);
}
});

router.post('/login', isNotLoggedIn, (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if (err) {
console.log(err);
return next(err);
}
if (info) {
return res.status(403).send(info.reason);
}
return req.login(user, async (loginErr) => {
if (loginErr) {
console.log('loginErr', loginErr);
console.log('user', user);
return next(loginErr);
}
const fullUserWithoutPassword = await User.findOne({
where: { id: user.id },
attributes: {
exclude: ['password'],
},
include: [
{
model: Post,
attributes: ['id'],
},
{
model: User,
as: 'Followings',
attributes: ['id'],
},
{
model: User,
as: 'Followers',
attributes: ['id'],
},
],
});
console.log(fullUserWithoutPassword);
return res.status(200).json(fullUserWithoutPassword);
});
})(req, res, next);
});

router.post('/', isNotLoggedIn, async (req, res, next) => {
console.log(req.body);
try {
const exUser = await User.findOne({
where: {
email: req.body.email,
},
});
if (exUser) {
return res.status(403).send('이미 사용중인 아이디입니다.');
}
const hashedPassword = await bcrypt.hash(req.body.password, 12);
await User.create({
email: req.body.email,
nickname: req.body.nickname,
password: hashedPassword,
});
// res.setHeader('Access-Control-Allow-Origin', '*');
res.status(201).send('ok');
} catch (error) {
console.error(error);
next(error);
}
});
router.post('/logout', isLoggedIn, (req, res, next) => {
req.logout();
req.session.destroy();
res.send('ok');
});

module.exports = router;

routes) middlewares.js

const express = require('express');
const postRouter = require('./routes/post');
const userRouter = require('./routes/user');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const passport = require('passport');
const db = require('./models');
const cors = require('cors');
const passportConfig = require('./passport');
const app = express();
const dotenv = require('dotenv');

dotenv.config();

db.sequelize
.sync()
.then(() => {
console.log('db 연결!!');
})
.catch(console.error);
passportConfig();

app.use(express.json());
app.use(
cors({
origin: 'http://localhost:3060',
credentials: true,
})
);
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
session({
saveUninitialized: false,
resave: false,
secret: process.env.COOKIE_SECRET,
})
);
app.use(passport.initialize());
app.use(passport.session());

app.get('/', (req, res) => {
res.send('hello express');
});

app.use('/post', postRouter);
app.use('/user', userRouter);

app.listen(3065, () => {
console.log('서버 실행 중!!! ');
});

app.js

const express = require('express');
const postRouter = require('./routes/post');
const userRouter = require('./routes/user');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const passport = require('passport');
const db = require('./models');
const cors = require('cors');
const passportConfig = require('./passport');
const app = express();
const dotenv = require('dotenv');

dotenv.config();

db.sequelize
.sync()
.then(() => {
console.log('db 연결!!');
})
.catch(console.error);
passportConfig();

app.use(express.json());
app.use(
cors({
origin: 'http://localhost:3060',
credentials: true,
})
);
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
session({
saveUninitialized: false,
resave: false,
secret: process.env.COOKIE_SECRET,
})
);
app.use(passport.initialize());
app.use(passport.session());

app.get('/', (req, res) => {
res.send('hello express');
});

app.use('/post', postRouter);
app.use('/user', userRouter);

app.listen(3065, () => {
console.log('서버 실행 중!!! ');
});

강의와 관련있는 질문을 남겨주세요.
• 강의와 관련이 없는 질문은 지식공유자가 답변하지 않을 수 있습니다. (사적 상담, 컨설팅, 과제 풀이 등)
• 질문을 남기기 전, 비슷한 내용을 질문한 수강생이 있는지 먼저 검색을 해주세요. (중복 질문을 자제해주세요.)
서비스 운영 관련 질문은 인프런 우측 하단 ‘문의하기’를 이용해주세요. (영상 재생 문제, 사이트 버그, 강의 환불 등)

질문 전달에도 요령이 필요합니다.
• 지식공유자가 질문을 좀 더 쉽게 확인할 수 있게 도와주세요.
• 강의실 페이지(/lecture) 에서 '질문하기'를 이용해주시면 질문과 연관된 수업 영상 제목이 함께 등록됩니다.
• 강의 대시보드에서 질문을 남길 경우, 관련 섹션 및 수업 제목을 기재해주세요. 
• 수업 특정 구간에 대한 질문은 꼭 영상 타임코드를 남겨주세요!

구체적인 질문일수록 명확한 답을 받을 수 있어요.
• 질문 제목은 핵심 키워드를 포함해 간결하게 적어주세요.
• 질문 내용은 자세하게 적어주시되, 지식공유자가 답변할 수 있도록 구체적으로 남겨주세요.
• 정확한 질문 내용과 함께 코드를 적어주시거나, 캡쳐 이미지를 첨부하면 더욱 좋습니다.

기본적인 예의를 지켜주세요.
• 정중한 의견 및 문의 제시, 감사 인사 등의 커뮤니케이션은 더 나은 강의를 위한 기틀이 됩니다. 
• 질문이 있을 때에는 강의를 만든 지식공유자에 대한 기본적인 예의를 꼭 지켜주세요. 
반말, 욕설, 과격한 표현 등 지식공유자를 불쾌하게 할 수 있는 내용은 스팸 처리 등 제재를 가할 수 있습니다. 

답변 2

1

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

쿠키 문제는 프론트에서 axios 요청을 할 때 withCredentials: true를 했는지, 서버에서 cors와 credentials를 제대로 설정했는지 체크해보셔야 합니다.

아직 https 배포는 안 하셨죠?

0

임수진님의 프로필 이미지
임수진
질문자

와우 .. 해결됐어요 강의 들으면서 withCredentials: true 부분을 놓쳤나봅니다! ㅠㅡㅠ 감사합니다!

임수진님의 프로필 이미지
임수진

작성한 질문수

질문하기