Passport(passport-local)

๐Ÿ‘Passport ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

passport๋Š” Node.js์˜ ์ธ์ฆ ๋ฏธ๋“ค์›จ์–ด๋กœ ์š”์ฒญ์— ๋Œ€ํ•œ ์ธ์ฆ์„ ์œ„ํ•œ ํŒจํ‚ค์ง€์ด๋‹ค. ์†Œ์…œ๋„คํŠธ์›Œํฌ ์„œ๋น„์Šค์˜ ๋ฐœ์ „์œผ๋กœ ์ธํ•ด OAuth ์ธ์ฆ ๋ฐฉ์‹์˜ ์‚ฌ์šฉ์ด ๋ณดํŽธํ™” ๋˜๋ฉด์„œ API๋ฅผ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ์‹์„ ๊ตฌ์ถ•ํ•ด์ฃผ๋Š” ํŒจํ‚ค์ง€์ด๋‹ค.

๐Ÿ‘passport-local

passport์˜ ์ „๋žต์ค‘ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋กœ์ปฌ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•ด๋ณด๋„๋ก ํ•˜์ž. ์†Œ์…œ ๋กœ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๊ธฐ์ „ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ธ ๋กœ์ปฌ์„ ์‚ฌ์šฉํ•ด๋ณด๋ฉฐ passport๊ฐ€ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ๊ตฌ๋™๋˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด๊ฒ ๋‹ค.

๋จผ์ € passport๋Š” ์š”์ฒญ์„ ์ธ์ฆํ•˜๊ธฐ ์œ„ํ•ด ์ „๋žต์ด๋ผ๋Š” ๊ฒƒ์„ ์‚ฌ์šฉํ•œ๋‹ค. ์šฐ๋ฆฌ๋Š” local ์ „๋žต์„ ๊ตฌํ˜„ํ•˜์—ฌ local์ธ์ฆ์—์„œ ์š”์ฒญ์„ passport์—๊ฒŒ ์ „๋‹ฌ ํ•  ๊ฒƒ์ด๋‹ค.

๋จผ์ € ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋ฅผ ๋‹ค์šด๋กœ๋“œ ํ•œ๋‹ค.
npm i passport passport-local

ํŒจํ‚ค์ง€ ๋‹ค์šด๋กœ๋“œ ํ›„ local ์ „๋žต ํŒŒ์ผ์„ ๊ตฌ์„ฑํ•ด์ค€๋‹ค. ์ „๋žต์ด๋ผ๋Š” ๊ฒƒ์€ ๊ณง ์šฐ๋ฆฌ๊ฐ€ ๋กœ๊ทธ์ธ์„ ์ฒ˜๋ฆฌํ•  ๊ณผ์ •์„ ๋‚˜์—ดํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');

const User = require('../models/user');

module.exports = () => {
// passport.authenticate('local' ...์—์„œ์ด๋™ํ•ด์„œ ๋ฐ‘์˜ ๋กœ์ง์ด ์‹คํ–‰๋œ๋‹ค.
passport.use(new LocalStrategy({
usernameField: 'email', // req.body.email ํ•„๋“œ์™€ req ๊ฐ’์ด ์ผ์น˜ํ•ด์•ผ๋จ
passwordField: 'password', // req.body.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);
} else { // ๋น„๋ฐ€๋ฒˆํ˜ธ ๋‹ค๋ฆ„
done(null, false, { message: '๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.'});
}
} else { // ๊ฐ€์ž…๋œ ์ด๋ฉ”์ผ์ด ์—†๋‹ค๋ฉด
done(null, false, { message: '๊ฐ€์ž…๋˜์ง€ ์•Š์€ ํšŒ์›์ž…๋‹ˆ๋‹ค.'});
}
// doneํ•จ์ˆ˜ ํ˜ธ์ถœ ํ›„ passport.authenticate ๋‚˜๋จธ์ง€ ์‹คํ–‰
} catch (error) {
console.log(error);
done(error);
}
}));
};

์ „๋žตํŒŒ์ผ์˜ ๊ตฌ์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ๋กœ๊ทธ์ธ์‹œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ›๋Š” ์•„์ด๋”” ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •๋ณด๋ฅผ username, passwordํ•„๋“œ์— ๊ฐ’์„ ๋„ฃ์–ด์ค€๋‹ค. ๊ธฐ๋ณธ ํ•„๋“œ๊ฐ’์€ username, password์ด๋ฏ€๋กœ ์„œ๋น„์Šค์—์„œ body์— ๋‹ด๋Š” ์ •๋ณด์˜ ์ด๋ฆ„๊ณผ ๊ธฐ๋ณธ๊ฐ’์ด ๋‹ค๋ฅด๋ฉด ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

์ดํ›„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์œ ์ €๋ฅผ ์ฐพ๊ณ  ์žˆ๋‹ค๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋น„๊ตํ•˜๊ณ  ์ผ์น˜ํ•˜๋ฉด ํ•ด๋‹น ์œ ์ €๋ฅผ ๋ฆฌํ„ดํ•ด์ค€๋‹ค.
ํ•ด๋‹น ๊ณผ์ •์—์„œ done์ด๋ผ๋Š” ์ฝœ๋ฐฑ ๋ฉ”์„œ๋“œ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š”๋ฐ done๋ฉ”์„œ๋“œ์— ๋“ค์–ด๊ฐ€๋Š” ์ธ์ž๊ฐ’์€ **done(err, data)**์ด๋‹ค.
์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด ์ž…๋ ฅ๋ฐ›์€ ์ •๋ณด์— ์ผ์น˜ํ•˜๋Š” ์œ ์ €๊ฐ€ ์žˆ์„๋•Œ๋Š” ์ฒซ ๋ฒˆ์งธ ์ธ์ž๊ฐ’์€ null๋กœ error๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ์œ ์ €์˜ ์ •๋ณด๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ์•„๋‹Œ์ง€ ์กฐํšŒ ํ›„ ์„ฑ๊ณต์‹œ ์œ ์ € ๋ฐ์ดํ„ฐ ์—†์„ ์‹œ ์—๋Ÿฌ๋ฅผ doneํ•จ์ˆ˜์— ์ „๋‹ฌํ•ด ๋ฆฌํ„ดํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์ด๋ ‡๊ฒŒ ์œ ์ €์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๊ณ  ๋ฆฌํ„ดํ•œ ๊ฐ’์„ passport์—์„œ๋Š” ์„ธ์…˜์œผ๋กœ ์ƒ์„ฑํ•ด์ค€๋‹ค.๐Ÿ‘๐Ÿ‘๐Ÿ‘


๐Ÿ‘์„ธ์…˜ ์ƒ์„ฑ

1
2
3
4
5
6
7
8
9
10
11
12
13
passport.serializeUser((user, done ) => {
done(null, user.id ); // ์„ธ์…˜์— user.id๋งŒ ์ €์žฅ
});

// ์„ธ์…˜์— ์ €์žฅ๋œ id๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ์ฒด๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
// deserializeUser์˜ id ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” serializeUser์—์„œ done์— ๋‹ด์•˜๋˜ ๋‘๋ฒˆ์งธ ์ธ์ˆ˜๊ฐ€ ์˜ค๊ฒŒ๋œ๋‹ค.
// ๊ฒฐ๊ณผ๊ฐ’ done์˜ user๋Š” req.user๋กœ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.
passport.deserializeUser((id, done) => {

User.findOne({ where: { id } })
.then(user => done(null, user))
.catch(err => done(err));
});

serialize, deserialize ํ•จ์ˆ˜๋Š” passport์—์„œ ์„ธ์…˜์„ ์ƒ์„ฑํ•˜๊ณ  ์ƒ์„ฑ๋œ ์„ธ์…˜๊ฐ’์„ ํ†ตํ•œ ์œ ์ €์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค.
serialize ํ•จ์ˆ˜๋Š” ์ „๋žต ํŒŒ์ผ์—์„œ ๋ฆฌํ„ดํ•œ ๊ฐ’์„ ๋ฐ›์•„ ์œ ์ €์˜ ์ •๋ณด๋ฅผ ์„ธ์…˜์œผ๋กœ ๋‹ด์•„ ์ƒ์„ฑํ•ด์ค€๋‹ค. ์•„์ฃผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์„ธ์…˜์„ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

๐Ÿ‘์„ธ์…˜ ์„ค์ •

passport์—์„œ ์„ธ์…˜์„ ์ƒ์„ฑํ•ด์ค€๋‹ค. ํ•˜์ง€๋งŒ express์—์„œ passport๊ฐ€ ์ƒ์„ฑํ•œ ์„ธ์…˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ช‡๊ฐ€์ง€ ์„ค์ •์ด ํ•„์š”ํ•˜๋‹ค.
์„ค์ •์€ app.js ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ด๋ฃจ์–ด์ง„๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
app.use(session({
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},

}));
app.use(passport.initialize()); //passport
app.use(passport.session()); // passport

express์— passport๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  passport๊ฐ€ ์„ธ์…˜์„ ์ด์šฉํ•œ๋‹ค๋Š” ์„ค์ •์„ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
์ด์ œ local์ „๋žต์ด ๊ตฌ์„ฑ๋˜์—ˆ์œผ๋‹ˆ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด์ž.


โœ…ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ๋Š” ํด๋ก ์ฝ”๋”ฉ์„ ์ง„ํ–‰์ค‘์ด๋˜ ํ”„๋กœ์ ํŠธ์—์„œ ์ง„ํ–‰ ํ•˜์˜€๋‹ค.


๋กœ๊ทธ์ธ์„ ์œ„ํ•œ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๋กœ๊ทธ์ธ์„ ์ง„ํ–‰ํ•œ๋‹ค.


์š”์ฒญ์ด 200 StatusCode์™€ ํ•จ๊ป˜ ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๊ฐ€ ๋˜์—ˆ๋‹ค.


๋„คํŠธ์›Œํฌ ํƒญ์„ ํ†ตํ•ด ์„ธ์…˜๊นŒ์ง€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๋ ‡๊ฒŒ passport์˜ local์ „๋ ฅ์„ ์‹คํ–‰ํ•ด ๋ณด์•˜๋‹ค. ์ดํ›„ ์†Œ์…œ๋กœ๊ทธ์ธ API๋ฅผ ํ†ตํ•ด passport์ „๋žต์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ณผ์ •๊นŒ์ง€ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.


Author

han Ju Ryeon

Posted on

2021-09-09

Updated on

2021-12-05

Licensed under

๋Œ“๊ธ€