...

Passport ๋ชจ๋
Passport๋ ์ด๋ฆ ๊ทธ๋๋ก ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ๋ ํด์ฃผ๋ ์ฌ๊ถ ๊ฐ์ ์ญํ ์ ํ๋ ๋ชจ๋์ด๋ค.
ํ์๊ฐ์ ๊ณผ ๋ก๊ทธ์ธ์ ์ง์ ๊ตฌํํ ์๋ ์์ง๋ง, ์ธ์ ๊ณผ ์ฟ ํค ์ฒ๋ฆฌ ๋ฑ ๋ณต์กํ ์์ ์ด ๋ง์ผ๋ฏ๋ก ๊ฒ์ฆ๋ ๋ชจ๋์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
๊ทธ๋ฐ ๋ฐฉ๋ฉด์์, Passport๋ ์ฌ์ฉํ๊ธฐ ์ข์ ๊ฒ์ฆ๋ ๋ชจ๋์ด๋ค.
์๋ฅผ๋ค์๋ฉด, ์ฌ๊ถ์ด๋ผ๋ ๊ฒ์ ์ /์ถ๊ตญ ์ฌ์ฌ์์ ํด๋น ์ฌ๊ถ ์์ง์๊ฐ ์ /์ถ๊ตญ ์๊ฒฉ์ ๋ํด ์ธ์ฆํ๋ ์ญํ ์ ํ๋ค.
์ด๋ฅผ ์๋ฒ์ ๋น๊ตํด๋ณด๋ฉด, ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ์์ฒญํ ์๊ฒฉ์ด ์๋์ง ์ธ์ฆํ ๋์ passport ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
์์ฆ์๋ ์๋น์ค์ ๋ก๊ทธ์ธํ ๋ ์์ด๋์ ๋น๋ฐ๋ฒํธ ์ด์ธ์ ๊ตฌ๊ธ, ํ์ด์ค๋ถ, ์นด์นด์ค ๊ฐ์ ๊ธฐ์กด์ SNS ์๋น์ค ๊ณ์ ์ ์ด์ฉํ์ฌ ๋ก๊ทธ์ธ ํ๋๋ฐ, passport๋ชจ๋์ด ๋ฐ๋ก ์ฌ๊ธฐ์ ์ฌ์ฉ๋๋ ๊ฒ์ด๋ค.
์ ๋ฆฌํ์๋ฉด, passport๋ชจ๋์ ๋ก๊ทธ์ธ ์ ์ฐจ๋ฅผ ํ์คํ๊ฒ ํ๊ธฐ์ํด ์ฌ์ฉํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ธ ์ ์ด๋ค.
...๋ค์ด๊ฐ๊ธฐ์ ์์ ๐
passport ๋ฌธ๋ฒ์ ๊ต์ฅํ ๋ํดํ๊ณ ์ด๋ ต๋ค.
๋ฐ๋ผ์ ๋ณธ ๊ฐ์๋ passport์ฒ๋ฆฌ๊ณผ์ ์ ํ๋ํ๋์ฉ ์์ธํ ๋ค๋ฃฐ ์์ ์ด๋ค.
๋จผ์ ๊ทธ๋ฆผ์ผ๋ก ์ด๋ป๊ฒ ์์๋๋ก ์ฒ๋ฆฌ๋๋์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ๋ฐ๋ก ๋ค์, ์์ธํ ์ฝ๋ ์ค๋ช
์ ํตํด ๊ฐ์๋ฅผ ์ด์ด ๋๊ฐ ์์ ์ด๋ค.
์ฝ๋ ๋ฌธ๋ฒ๊ณผ ์ฒ๋ฆฌ๊ณผ์ ๊ทธ๋ฆผ์ ๊ณ์ ๋ฒ๊ฐ์ ๋ณด๋ฉฐ ์ดํดํ๋ ๊ฒ์ ๊ฐ๋ ฅ์ด ๊ถ์ฅํ๋ค.
passport.js ๋ผ์ด๋ธ๋ฌ๋ฆฌ
Passport.js
Simple, unobtrusive authentication for Node.js
www.passportjs.org
- strategy(์ ๋ต)์ ๋ฐ๋ฅธ ์์ฒญ์ผ๋ก ์ธ์ฆํ๊ธฐ ์ํ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉ
- strategy ์ข
๋ฅ (๋ก๊ทธ์ธ ์ธ์ฆ ๋ฐฉ์) :
- Local Strategy(passport-local) : ๋ก์ปฌ DB์์ ๋ก๊ทธ์ธ ์ธ์ฆ ๋ฐฉ์
- Social Authentication (passport-kakao, passport-twitter ๋ฑ) : ์์ ๋คํธ์ํฌ ๋ก๊ทธ์ธ ์ธ์ฆ ๋ฐฉ์
- API ๋์ : ์ฌ์ฉ์๊ฐ passport์ ์ธ์ฆ ์์ฒญ -> passport๋ ์ธ์ฆ ์ฑ๊ณต/์คํจ์ ์ด๋ค ์ ์ด๋ฅผ ํ ์ง ๊ฒฐ์
passport ์ค์น
๋จผ์ passport ๊ด๋ จ ํจํค์ง๋ค์ ์ค์นํ๋ค.
๋น๋ฐ๋ฒํธ ์ํธํ๋ฅผ ์ํด bcrypt๋ ๊ฐ์ด ์ค์น ํ๋ค.
[NODE] ๐ bcrypt ๋ชจ๋ (์๋ฆฌ & ์ฌ์ฉ๋ฒ)
์ํธํ ์๋ฆฌ [NODE] ๐ crypto ๋ชจ๋ (์ํธํ) ๋จ๋ฐฉํฅ ์ํธํ / ์๋ฐฉํฅ ์ํธํ ์ํธํ๋ฅผ ํ๋ ์ด์ ๋ ํด๋น ์ ๋ณด๊ฐ ์ค์ํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ํธํ์๋ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ ์ ์๋ค. ๋จ๋ฐฉํฅ์ ์ํธํํ
inpa.tistory.com
> npm install passport passport-local passport-kakao bcrypt
passport ํจํด ๊ตฌ์กฐ
passport๋ผ๋ ํด๋๋ฅผ ๋ง๋ค๊ณ ๊ทธ์์ ์ ๋ต ํ์ผ๋ค์ ๋ฃ์ด์ฃผ์.
๋ก๊ทธ์ธ ์ธ์ฆ ์ ๋ต์ ๋๊ฐ์ง๋ก ์ ํ๋ค.
ํ๋๋ ๋ก์ปฌ ์ธ์ฆ์ ๋ต์ด๊ณ , ๋ค๋ฅธ ํ๋๋ ์นด์นด์ค ์ธ์ฆ์ ๋ต ์ผ๋ก ๊ตฌ์ฑ๋์ด ์๋ค.
๋ณธ ๊ฐ์ข๋ ๋ก์ปฌ ์ธ์ฆ์ ๋ต์ ์ฐ์ ์ผ๋ก ์๊ฐํ ์์ ์ด๋ค.

passport ์ฒ๋ฆฌ ๊ณผ์
passport ์ด๊ธฐ ๋ก๊ทธ์ธ ๊ณผ์
1. ๋ก๊ทธ์ธ ์์ฒญ์ด ๋ผ์ฐํฐ๋ก ๋ค์ด์ด.
2. ๋ฏธ๋ค์จ์ด๋ฅผ ๊ฑฐ์น๊ณ , passport.authenticate() ํธ์ถ
3. authenticate์์ passport/localStrategy.js ํธ์ถ

4. ๋ก๊ทธ์ธ ์ ๋ต์ ์คํํ๊ณ , done()์ ํธ์ถํ๋ฉด, ๋ค์ passport.authenticate() ๋ผ์ฐํฐ๋ก ๋์๊ฐ ๋ค์ ๋ฏธ๋ค์จ์ด๋ฅผ ์คํ

+ done() ํจ์ ์ธ์๊ฐ์ ๋ฐ๋ฅธ ์ฌ๋ฌ ๋์

5. done()์ ๋ณด๋ฅผ ํ ๋๋ก, ๋ก๊ทธ์ธ ์ฑ๊ณต ์ ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ฒด์ ํจ๊ป req.login()๋ฅผ ์๋์ผ๋ก ํธ์ถ
6. req.login ๋ฉ์๋๊ฐ passport.serializeUser() ํธ์ถ (passport/index.js)
7. req.session์ ์ฌ์ฉ์ ์์ด๋ ํค๊ฐ๋ง ์ ์ฅ (๋ฉ๋ชจ๋ฆฌ ์ต์ ํ๋ฅผ ์ํด์)
8. passport.deserializeUser()๋ก ๋ฐ๋ก ๋์ด๊ฐ์ sql์กฐํํ req.user ๊ฐ์ฒด๋ฅผ ๋ฑ๋กํ, done() ๋ฐํํ์ฌ req.login ๋ฏธ๋ค์จ์ด๋ก ๋ค์ ๋๋์๊ฐ.
9. ๋ฏธ๋ค์จ์ด ์ฒ๋ฆฌํ, res.redirect('/')์ ์๋ตํ๋ฉด, ์ธ์ ์ฟ ํค๋ฅผ ๋ธ๋ผ์ฐ์ ์ ๋ณด๋ด๊ฒ ๋๋ค.
10. ๋ก๊ทธ์ธ ์๋ฃ ์ฒ๋ฆฌ (์ด์ ์ธ์ ์ฟ ํค๋ฅผ ํตํด์ ํต์ ํ๋ฉฐ ๋ก๊ทธ์ธ๋จ ์ํ๋ฅผ ์ ์ ์๋ค.)

passport ๋ก๊ทธ์ธ ์ดํ ๊ณผ์
1. ๋ชจ๋ ์์ฒญ์ passport.session() ๋ฏธ๋ค์จ์ด๊ฐ passport.deserializeUser() ๋ฉ์๋๋ฅผ ๋งค๋ฒ ํธ์ถํ๋ค.
2. deserializeUser์์ req.session์ ์ ์ฅ๋ ์์ด๋๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฌ์ฉ์ ์กฐํ
3. ์กฐํ๋ ์ฌ์ฉ์ ์ ์ฒด ์ ๋ณด๋ฅผ req.user ๊ฐ์ฒด์ ์ ์ฅ
4. ์ด์ ๋ถํฐ ๋ผ์ฐํฐ์์ req.user๋ฅผ ๊ณต์ฉ์ ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ๋๋ค.

passport ๊ตฌ์กฐ ์ฝ๋
app.js
...
const passport = require('passport');
...
const passportConfig = require('./passport');
...
const authRouter = require('./routes/auth'); // ์ธ์ฆ ๋ผ์ฐํฐ
const app = express();
passportConfig(); // ํจ์คํฌํธ ์ค์
...
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
session({
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
}),
);
//! express-session์ ์์กดํ๋ฏ๋ก ๋ค์ ์์นํด์ผ ํจ
app.use(passport.initialize()); // ์์ฒญ ๊ฐ์ฒด์ passport ์ค์ ์ ์ฌ์
app.use(passport.session()); // req.session ๊ฐ์ฒด์ passport์ ๋ณด๋ฅผ ์ถ๊ฐ ์ ์ฅ
// passport.session()์ด ์คํ๋๋ฉด, ์ธ์
์ฟ ํค ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ํด์ passport/index.js์ deserializeUser()๊ฐ ์คํํ๊ฒ ํ๋ค.
//* ๋ผ์ฐํฐ
app.use('/auth', authRouter);
...
- passport.initialize ๋ฏธ๋ค์จ์ด๋ ์์ฒญ (req ๊ฐ์ฒด) ์ passport ์ค์ ์ ์ฌ๊ณ ,
- passport.session ๋ฏธ๋ค์จ์ด๋ req.session ๊ฐ์ฒด์ passport ์ธ์ฆ ์๋ฃ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ค.
req.session ๊ฐ์ฒด๋ express-session์์ ์์ฑํ๋ ๊ฒ์ด๋ฏ๋ก, ๋ฐ๋ผ์ passport ๋ฏธ๋ค์จ์ด๋ express-session ๋ฏธ๋ค์จ์ด๋ณด๋ค ๋ค์ ์ฐ๊ฒฐํด์ผ ํ๋ค.
route/middlewares.js
: ์์ ์ด ๋ง๋ ๊ฐ๋จํ ์ฌ์ฉ์ ๋ฏธ๋ค์จ์ด ํจ์ ํ์ผ.
- ๋ก๊ทธ์ธ์ ๊ผญ ํด์ผ๋๋ ํ์ด์ง์, ํ์ง ์์๋ ๋๋ ํ์ด์ง ๊ตฌ๋ถํ๋ ๋ฏธ๋ค์จ์ด ์์ฑ
- req.isAuthenticated ํจ์๋ฅผ ์ด์ฉํ์ฌ ์์ฒญ์ ์ธ์ฆ์ฌ๋ถ ํ์ธ
//* ์ฌ์ฉ์ ๋ฏธ๋ค์จ์ด๋ฅผ ์ง์ ๊ตฌํ
exports.isLoggedIn = (req, res, next) => {
// isAuthenticated()๋ก ๊ฒ์ฌํด ๋ก๊ทธ์ธ์ด ๋์ด์์ผ๋ฉด
if (req.isAuthenticated()) {
next(); // ๋ค์ ๋ฏธ๋ค์จ์ด
} else {
res.status(403).send('๋ก๊ทธ์ธ ํ์');
}
};
exports.isNotLoggedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
next(); // ๋ก๊ทธ์ธ ์๋์ด์์ผ๋ฉด ๋ค์ ๋ฏธ๋ค์จ์ด
} else {
const message = encodeURIComponent('๋ก๊ทธ์ธํ ์ํ์
๋๋ค.');
res.redirect(`/?error=${message}`);
}
};
๋ก๊ทธ์ธ์ ํด๋นํ๋ ์ ๋ต์ ์ง์ผํ๋๋ฐ,
๋ก๊ทธ์ธํ ์ฌ์ฉ์๋ ํ์๊ฐ์ ๊ณผ ๋ก๊ทธ์ธ ๋ผ์ฐํฐ์ ์ ๊ทผํ๋ฉด ์๋๋ฉฐ,
๋ก๊ทธ์ธ์ ํ์ง ์์ ์ฌ์ฉ์๋ ๋ก๊ทธ์์ ๋ผ์ฐํฐ์ ์ ๊ทผํ๋ฉด ์๋๋ค.
๋ฐ๋ผ์ ๋ผ์ฐํฐ์ ์ ๊ทผ ๊ถํ์ ์ ์ดํ๋ ๋ฏธ๋ค์จ์ด๊ฐ ํ์ํ๋ค.
Passport๋ req๊ฐ์ฒด์ isAuthenticated๋ผ๋ ๋ฉ์๋๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ด์ค๋ค.
๋ก๊ทธ์ธ์ด ๋์ด์๋ค๋ฉด req.isAuthenticated()๊ฐ true์ผ ๊ฒ์ด๊ณ , ๊ทธ๋ ์ง ์๋ค๋ฉด false์ผ ๊ฒ์ด๋ค.
๋ฐ๋ผ์ ์ด ๋ฉ์๋๋ฅผ ํตํด ๋ก๊ทธ์ธ ์ฌ๋ถ๋ฅผ ํ์ ํ ์ ์๋ค.
auth.js ๋ผ์ฐํฐ์ ๋ก๊ทธ์ธ ์ฌ๋ถ๋ฅผ ๊ฒ์ฌํ๋ ์ ๋ฏธ๋ค์จ์ด๋ค์ ๋ฃ์ด ์ํ์ง ์๋ ์ํฉ๋ค์ ๋ฐฉ์งํ ์ ์๋ค.
route/auth.js
: ํ์๊ฐ์ , ๋ก๊ทธ์ธ, ๋ก๊ทธ์์ ์ฒ๋ฆฌ๋ฅผ ๋ด๋นํ๋ ๋ผ์ฐํฐ. ๋ก๊ทธ์ธ ์ธ์ฆ์ ๊ดํด passportํด๋๋ก ์ธ์ฆ์ ๋ต์ ์์ฒญํ๋ค.
- /logout ๊ฒฝ๋ก๋ก ์ ๊ทผํ์์ ๋ ๋ก๊ทธ์ธ์ด ๋์ด์์ง ์๋ค๋ฉด ์ ๊ทผํ ์ ์๋๋ก ํด์ผ ํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ isLoggedIn์ ๋ฏธ๋ค์จ์ด๋ก ๋ฃ์ด์ฃผ์๊ณ ,
- /join ๊ฒฝ๋ก๋ก ์ ๊ทผํ์์ ๋ ๋ก๊ทธ์์์ด ๋์ด์์ง ์๋ค๋ฉด (์ฆ, ํ์ฌ ๋ก๊ทธ์ธํ ์ํ๋ผ๋ฉด) ์ ๊ทผํ ์ ์๋๋ก ํด์ผํ๊ธฐ ๋๋ฌธ์ isNotLoggedIn์ ๋ฏธ๋ค์จ์ด๋ก ๋ฃ์ด์ฃผ์๋ค.
const express = require('express');
const passport = require('passport');
const bcrypt = require('bcrypt');
const { isLoggedIn, isNotLoggedIn } = require('./middlewares'); // ๋ด๊ฐ ๋ง๋ ์ฌ์ฉ์ ๋ฏธ๋ค์จ์ด
const User = require('../models/user');
const router = express.Router();
//* ํ์ ๊ฐ์
// ์ฌ์ฉ์ ๋ฏธ๋ค์จ์ด isNotLoggedIn์ ํต๊ณผํด์ผ async (req, res, next) => ๋ฏธ๋ค์จ์ด ์คํ
router.post('/join', isNotLoggedIn, async (req, res, next) => {
const { email, nick, password } = req.body; // ํ๋ก ํธ์์ ๋ณด๋ธ ํผ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋๋ค.
try {
// ๊ธฐ์กด์ ์ด๋ฉ์ผ๋ก ๊ฐ์
ํ ์ฌ๋์ด ์๋ ๊ฒ์ฌ (์ค๋ณต ๊ฐ์
๋ฐฉ์ง)
const exUser = await User.findOne({ where: { email } });
if (exUser) {
return res.redirect('/join?error=exist'); // ์๋ฌํ์ด์ง๋ก ๋ฐ๋ก ๋ฆฌ๋ค์ด๋ ํธ
}
// ์ ์์ ์ธ ํ์๊ฐ์
์ ์ฐจ๋ฉด ํด์ํ
const hash = await bcrypt.hash(password, 12);
// DB์ ํด๋น ํ์์ ๋ณด ์์ฑ
await User.create({
email,
nick,
password: hash, // ๋น๋ฐ๋ฒํธ์ ํด์๋ฌธ์๋ฅผ ๋ฃ์ด์ค๋ค.
});
return res.redirect('/');
} catch (error) {
console.error(error);
return next(error);
}
});
/* **************************************************************************************** */
//* ๋ก๊ทธ์ธ ์์ฒญ
// ์ฌ์ฉ์ ๋ฏธ๋ค์จ์ด isNotLoggedIn ํต๊ณผํด์ผ async (req, res, next) => ๋ฏธ๋ค์จ์ด ์คํ
router.post('/login', isNotLoggedIn, (req, res, next) => {
//? local๋ก ์คํ์ด ๋๋ฉด localstrategy.js๋ฅผ ์ฐพ์ ์คํํ๋ค.
passport.authenticate('local', (authError, user, info) => {
//? (authError, user, info) => ์ด ์ฝ๋ฐฑ ๋ฏธ๋ค์จ์ด๋ localstrategy์์ done()์ด ํธ์ถ๋๋ฉด ์คํ๋๋ค.
//? localstrategy์ done()ํจ์์ ๋ก์ง ์ฒ๋ฆฌ์ ๋ฐ๋ผ 1,2,3๋ฒ์งธ ์ธ์์ ๋ฃ๋ ์์๊ฐ ๋ฌ๋๋๋ฐ ๊ทธ ์ด์ ๊ฐ ๋ฐ๋ก ์ด๊ฒ์ด๋ค.
// done(err)๊ฐ ์ฒ๋ฆฌ๋ ๊ฒฝ์ฐ
if (authError) {
console.error(authError);
return next(authError); // ์๋ฌ์ฒ๋ฆฌ ๋ฏธ๋ค์จ์ด๋ก ๋ณด๋ธ๋ค.
}
// done(null, false, { message: '๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.' }) ๊ฐ ์ฒ๋ฆฌ๋ ๊ฒฝ์ฐ
if (!user) {
// done()์ 3๋ฒ์งธ ์ธ์ { message: '๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.' }๊ฐ ์คํ
return res.redirect(`/?loginError=${info.message}`);
}
//? done(null, exUser)๊ฐ ์ฒ๋ฆฌ๋๊ฒฝ์ฐ, ์ฆ ๋ก๊ทธ์ธ์ด ์ฑ๊ณต(user๊ฐ false๊ฐ ์๋ ๊ฒฝ์ฐ), passport/index.js๋ก ๊ฐ์ ์คํ์ํจ๋ค.
return req.login(user, loginError => {
//? loginError => ๋ฏธ๋ค์จ์ด๋ passport/index.js์ passport.deserializeUser((id, done) => ๊ฐ done()์ด ๋๋ฉด ์คํํ๊ฒ ๋๋ค.
// ๋ง์ผ done(err) ๊ฐ ๋ฌ๋ค๋ฉด,
if (loginError) {
console.error(loginError);
return next(loginError);
}
// done(null, user)๋ก ๋ก์ง์ด ์ฑ๊ณต์ ์ด๋ผ๋ฉด, ์ธ์
์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ์ฅํด๋์ ๋ก๊ทธ์ธ ์ํ๊ฐ ๋๋ค.
return res.redirect('/');
});
})(req, res, next); //! ๋ฏธ๋ค์จ์ด ๋ด์ ๋ฏธ๋ค์จ์ด์๋ ์ฝ๋ฐฑ์ ์คํ์ํค๊ธฐ์ํด (req, res, next)๋ฅผ ๋ถ์ธ๋ค.
});
/* **************************************************************************************** */
//* ๋ก๊ทธ์์ (isLoggedIn ์ํ์ผ ๊ฒฝ์ฐ)
router.get('/logout', isLoggedIn, (req, res) => {
// req.user (์ฌ์ฉ์ ์ ๋ณด๊ฐ ์์ ๋ค์ด์๋ค. ๋น์ฐํ ๋ก๊ทธ์ธ๋์ด์์ผ๋ ๋ก๊ทธ์์ํ๋ ค๋ ๊ฑฐ๋๊น)
req.logout();
req.session.destroy(); // ๋ก๊ทธ์ธ์ธ์ฆ ์๋จ์ผ๋ก ์ฌ์ฉํ ์ธ์
์ฟ ํค๋ฅผ ์ง์ฐ๊ณ ํ๊ดดํ๋ค. ์ธ์
์ฟ ํค๊ฐ ์๋ค๋ ๋ง์ ์ฆ ๋ก๊ทธ์์ ์ธ ๋ง.
res.redirect('/');
});
module.exports = router;
passport/index.js
: ์ธ์ฆ ์ ๋ต์ ๋ฑ๋กํ๊ณ , ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ฑฐ๋ ๋ถ๋ฌ์ฌ๋ ์ด์ฉ๋๋ ํ์ผ
const passport = require('passport');
const local = require('./localStrategy'); // ๋ก์ปฌ์๋ฒ๋ก ๋ก๊ทธ์ธํ ๋
//const kakao = require('./kakaoStrategy'); // ์นด์นด์ค์๋ฒ๋ก ๋ก๊ทธ์ธํ ๋
const User = require('../models/user');
module.exports = () => {
/*
* ใ
์ง๋ ฌํ(Serialization) : ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํํ์ฌ ์ ์ก ๊ฐ๋ฅํ ํํ๋ก ๋ง๋๋ ๊ฒ.
* ใ
์ญ์ง๋ ฌํ(Deserialization) : ์ง๋ ฌํ๋ ํ์ผ ๋ฑ์ ์ญ์ผ๋ก ์ง๋ ฌํํ์ฌ ๋ค์ ๊ฐ์ฒด์ ํํ๋ก ๋ง๋๋ ๊ฒ.
*/
//? req.login(user, ...) ๊ฐ ์คํ๋๋ฉด, serializeUser๊ฐ ์คํ๋๋ค.
//? ์ฆ ๋ก๊ทธ์ธ ๊ณผ์ ์ ํ ๋๋ง ์คํ
passport.serializeUser((user, done) => {
// req.login(user, ...)์ user๊ฐ ์ผ๋ก ์์ ๊ฐ์ ์ด์ฉํ ์ ์๋ ๊ฒ์ด๋ค.
done(null, user.id);
// req.session๊ฐ์ฒด์ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ง ์ ํ.
// user.id๋ง์ ์ธ์
๊ฐ์ฒด์ ๋ฃ์. ์ฌ์ฉ์์ ์จ๊ฐ ์ ๋ณด๋ฅผ ๋ชจ๋ ๋ค๊ณ ์์ผ๋ฉด,
// ์๋ฒ ์์๋ญ๋น๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์ ์์ด๋๋ง ์ ์ฅ ๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ๋ฅผ deserializeUser์ ์ ๋ฌํจ
// ์ธ์
์๋ { id: 3, 'connect.sid' : s%23842309482 } ๊ฐ ์ ์ฅ๋จ
});
//? deserializeUser๋ serializeUser()๊ฐ doneํ๊ฑฐ๋ passport.session()์ด ์คํ๋๋ฉด ์คํ๋๋ค.
//? ์ฆ, ์๋ฒ ์์ฒญ์ด ์ฌ๋๋ง๋ค ํญ์ ์คํํ์ฌ ๋ก๊ทธ์ธ ์ ์ ์ ๋ณด๋ฅผ ๋ถ๋ฌ์ ์ด์ฉํ๋ค.
passport.deserializeUser((id, done) => {
// req.session์ ์ ์ฅ๋ ์ฌ์ฉ์ ์์ด๋๋ฅผ ๋ฐํ์ผ๋ก DB ์กฐํ๋ก ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ป์ด๋ธ ํ req.user์ ์ ์ฅ.
// ์ฆ, id๋ฅผ sql๋ก ์กฐํํด์ ์ ์ฒด ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๋ณต๊ตฌ ๋ก์ง์ด๋ค.
User.findOne({ where: { id } })
.then(user => done(null, user)) //? done()์ด ๋๋ฉด ์ด์ ๋ค์ req.login(user, ...) ์ชฝ์ผ๋ก ๋๋์๊ฐ ๋ค์ ๋ฏธ๋ค์จ์ด๋ฅผ ์คํํ๊ฒ ๋๋ค.
.catch(err => done(err));
});
//^ ์์ ์ด๋ฌํ ์ผ๋ จ์ ๊ณผ์ ์, ๊ทธ๋ฅ ์ฒ์๋ถํฐ user๊ฐ์ฒด๋ฅผ ํต์งธ๋ก ์ฃผ๋ฉด ๋ ๊ป ๋ญ ์ง๋ ฌํ/์ญ์ง๋ ฌํ๋ฅผ ํ๋ ์ด์ ๋
//^ ์ธ์
๋ฉ๋ชจ๋ฆฌ๊ฐ ํ์ ๋์ด์๊ธฐ๋๋ฌธ์ ํจ์จ์ ์ผ๋ก ํ๊ธฐ์ํด, user.id๊ฐ ํ๋๋ง์ผ๋ก ๋ฐ์์์,
//^ ์ด๋ฅผ deserialize ๋ณต๊ตฌํด์ ์ฌ์ฉํ๋ ์์ผ๋ก ํ๊ธฐ ์ํด์๋ค.
/* ---------------------------------------------------------------------- */
local();
//kakao();
};
passport.serializeUser
- strategy์์ ๋ก๊ทธ์ธ ์ฑ๊ณต์ ํธ์ถํ๋ done(null, user) ํจ์์ ๋ ๋ฒ์งธ ์ธ์ user๋ฅผ ์ ๋ฌ ๋ฐ์ ์ธ์ (req.session.passport.user)์ ์ ์ฅ
- ๋ณดํต ์ธ์ ์ ๋ฌด๊ฒ๋ฅผ ์ค์ด๊ธฐ ์ํด, user์ id๋ง ์ธ์ ์ ์ ์ฅ
passport.deserializeUser
- ์๋ฒ๋ก ๋ค์ด์ค๋ ์์ฒญ๋ง๋ค ์ธ์ ์ ๋ณด๋ฅผ ์ค์ DB์ ๋น๊ต
- ํด๋น ์ ์ ์ ๋ณด๊ฐ ์์ผ๋ฉด done์ ํตํด req.user์ ์ฌ์ฉ์ ์ ์ฒด ์ ๋ณด๋ฅผ ์ ์ฅ (๊ทธ๋ฌ๋ฉด ๋ค๋ฅธ ๋ฏธ๋ค์จ์ด์์ req.user๋ฅผ ๊ณตํต์ ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅ)
- serializeUser์์ done์ผ๋ก ๋๊ฒจ์ฃผ๋ user๊ฐ deserializeUser์ ์ฒซ ๋ฒ์งธ ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌ๋๊ธฐ ๋๋ฌธ์ ๋์ ํ์ ์ ํญ์ ์ผ์น ํ์
passport/localStrategy.js
: ๋ก์ปฌ ์ธ์ฆ์ ๋ต ์ ์ฐจ ์ฝ๋๊ฐ ์๋ ํ์ผ์ด๋ฉฐ, ๋ผ์ฐํฐ์์ ์์ฒญ์ด ๋ค์ด์ค๋ฉด ์คํ๋๋ค.
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');
const User = require('../models/user');
module.exports = () => {
//? auth ๋ผ์ฐํฐ์์ /login ์์ฒญ์ด ์ค๋ฉด local์ค์ ๋๋ก ์ด์ชฝ์ด ์คํ๋๊ฒ ๋๋ค.
passport.use(
new LocalStrategy(
{
//* req.body ๊ฐ์ฒด์ธ์ ํ๊ณ ํค๊ฐ์ด ์ผ์นํด์ผ ํ๋ค.
usernameField: 'email', // req.body.email
passwordField: 'password', // req.body.password
/*
session: true, // ์ธ์
์ ์ ์ฅ ์ฌ๋ถ
passReqToCallback: false,
express์ req ๊ฐ์ฒด์ ์ ๊ทผ ๊ฐ๋ฅ ์ฌ๋ถ. true์ผ ๋, ๋ค์ callback ํจ์์์ req ์ธ์๊ฐ ๋ ๋ถ์.
async (req, email, password, done) => { } ๊ฐ ๋จ
*/
},
//* ์ฝ๋ฐฑํจ์์ email๊ณผ password๋ ์์์ ์ค์ ํ ํ๋์ด๋ค. ์์์ ๊ฐ์ฒด๊ฐ ์ ์ก๋๋ฉด ์ฝ๋ฐฑ์ด ์คํ๋๋ค.
async (email, password, done) => {
try {
// ๊ฐ์
๋ ํ์์ธ์ง ์๋์ง ํ์ธ
const exUser = await User.findOne({ where: { email } });
// ๋ง์ผ ๊ฐ์
๋ ํ์์ด๋ฉด
if (exUser) {
// ํด์๋น๋ฒ์ ๋น๊ต
const result = await bcrypt.compare(password, exUser.password);
if (result) {
done(null, exUser); //? ์ฑ๊ณต์ด๋ฉด done()์ 2๋ฒ์งธ ์ธ์์ ์ ์ธ
} else {
done(null, false, { message: '๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.' }); //? ์คํจ๋ฉด done()์ 2๋ฒ์งธ ์ธ์๋ false๋ก ์ฃผ๊ณ 3๋ฒ์งธ ์ธ์์ ์ ์ธ
}
//? done()์ ํธ์ถํ๋ฉด, /login ์์ฒญ์จ auth ๋ผ์ฐํฐ๋ก ๋ค์ ๋์๊ฐ์ ๋ฏธ๋ค์จ์ด ์ฝ๋ฐฑ์ ์คํํ๊ฒ ๋๋ค.
}
// DB์ ํด๋น ์ด๋ฉ์ผ์ด ์๋ค๋ฉด, ํ์ ๊ฐ์
ํ์ ์ด ์๋ค.
else {
done(null, false, { message: '๊ฐ์
๋์ง ์์ ํ์์
๋๋ค.' });
}
} catch (error) {
console.error(error);
done(error); //? done()์ ์ฒซ๋ฒ์งธ ํจ์๋ err์ฉ. ํน๋ณํ๊ฒ ์๋ ํ์์๋ null๋ก ์ฒ๋ฆฌ.
}
},
),
);
};
LocalStrategy
- local ๋ก๊ทธ์ธ์ ์ํ ์ ๋ต
- usernameField / passwordField : ํ๋ก ํธ๋จ์ ํผํ๊ทธ์์ ์์ฒญ๋ ๊ฐ๋ค์ด (req.body.*) ์ค๊ฒ ๋๋ค.
- session: ์ธ์ ์ ์ฅ์ฌ๋ถ
- passReqToCallback: express์ req ๊ฐ์ฒด์ ์ ๊ทผ ๊ฐ๋ฅ ์ฌ๋ถ
true์ผ ๋, ๋ค์ callback ํจ์์์ req ์ธ์๊ฐ ๋ ๋ถ์ (req, email, password, done) => {} - ์ฒซ ๋ฒ์งธ ์ธ์์์ id, pw๊ฐ ์ ์ก๋๋ฉด, ๋๋ฒ ์งธ ์ธ์ ์ฝ๋ฐฑํจ์ ์คํ. ์ค์ ์ ๋ต์ async ํจ์์์ ์คํ
- DB์์ ๋น๊ตํ์ฌ done ํจ์๋ฅผ ์ด์ฉํด user ๊ฐ์ฒด ์ ์ก, ๋๋ ์๋ฌ ๋ฆฌํด
- done(์๋ฌ, ์ฑ๊ณต, ์คํจ๊ฐ)
- ์ฒซ ๋ฒ์งธ ์ธ์: DB์กฐํ์ ๋ฐ์ํ๋ ์๋ฒ ์๋ฌ. ๋ฌด์กฐ๊ฑด ์คํจํ๋ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉ
- ๋ ๋ฒ์งธ ์ธ์: ์ฑ๊ณตํ์ ๋ returnํ ๊ฐ
- ์ธ ๋ฒ์งธ ์ธ์: ์ฌ์ฉ์๊ฐ ์์๋ก ์คํจ๋ฅผ ๋ง๋ค๊ณ ์ถ์ ๋ ์ฌ์ฉ
ex) ์์์ ๋น๋ฐ๋ฒํธ๊ฐ ํ๋ ธ๋ค๋ ์๋ฌ
์ด ๊ธ์ด ์ข์ผ์ จ๋ค๋ฉด ๊ตฌ๋ & ์ข์์
์ฌ๋ฌ๋ถ์ ๊ตฌ๋
๊ณผ ์ข์์๋
์ ์์๊ฒ ํฐ ํ์ด ๋ฉ๋๋ค.