๐9์ฅ ํค์๋๐
์ปจํธ๋กค๋ฌ
๋ผ์ฐํฐ์ ๋ฏธ๋ค์จ์ด
Passport
์นด์นด์ค ๋ก๊ทธ์ธ
multer
๐ MySQL๊ณผ Passport๋ฅผ ์ด์ฉํด ๋ก๊ทธ์ธ, ์ด๋ฏธ์ง ์ ๋ก๋, ๊ฒ์๊ธ ์์ฑ, ํด์ํ๊ทธ ๊ฒ์, ํ๋ก์ ๊ธฐ๋ฅ์ด ์๋ SNS ์๋น์ค๋ฅผ ์ ์
$ npm init
$ npm i sequelize mysql2 sequelize-cli
$ npx sequelize init
package.json ์์ฑ ํ ์ํ๋ผ์ด์ฆ๋ฅผ ์ค์น
exports.renderProfile = (req, res) => {
res.render('profile', { title: '๋ด ์ ๋ณด - NodeBird' });
};
exports.renderJoin = (req, res) => {
res.render('join', { title: 'ํ์๊ฐ์
- NodeBird' });
};
exports.renderMain = (req, res, next) => {
const twits = [];
res.render('main', {
title: 'NodeBird',
twits,
});
};
์๋น์ค๋ ํด๋น ์ปจํธ๋กค๋ฌ์ ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง์ ๋ด๋น,
์ปจํธ๋กค๋ฌ๋ ์์ฒญ(req)๊ณผ ์๋ต(res)์ ์ฒ๋ฆฌํ๋ ๋ด๋น
๐ MySQL๊ณผ ์ํ๋ผ์ด์ฆ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์
foreach๋ฅผ ์ฌ์ฉํด ๊ฐ๊ฐ์ ๋ชจ๋ธ๋ค์ ์ํ๋ผ์ด์ฆ ๊ฐ์ฒด์ ์ฐ๊ฒฐํ๋ ์ฝ๋
const Sequelize = require('sequelize');
const fs = require('fs');
const path = require('path');
const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const db = {};
const sequelize = new Sequelize(
config.database, config.username, config.password, config,
);
db.sequelize = sequelize;
const basename = path.basename(__filename);
fs
.readdirSync(__dirname) // ํ์ฌ ํด๋์ ๋ชจ๋ ํ์ผ์ ์กฐํ
.filter(file => { // ์จ๊น ํ์ผ, index.js, js ํ์ฅ์๊ฐ ์๋ ํ์ผ ํํฐ๋ง
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => { // ํด๋น ํ์ผ์ ๋ชจ๋ธ ๋ถ๋ฌ์์ init
const model = require(path.join(__dirname, file));
console.log(file, model.name);
db[model.name] = model;
model.initiate(sequelize);
});
Object.keys(db).forEach(modelName => { // associate ํธ์ถ
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
module.exports = db;
๐ ์ฝ์ : ๋ฐ์ดํฐ ๋ฒ ์ด์ค ์์ฑ
$ npx sequelize db:create
๐ app.js : ๋ชจ๋ธ ์๋ฒ์ ์ฐ๊ฒฐ
dotenv.config();
const pageRouter = require('./routes/page');
**const { sequelize } = require('./models');**
const app = express();
app.set('port', process.env.PORT || 8001);
app.set('view engine', 'html');
nunjucks.configure('views', {
express: app,
watch: true,
});
**sequelize.sync({ force: false })
.then(() => {
console.log('๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ฑ๊ณต');
})
.catch((err) => {
console.error(err);
});**
app.use(morgan('dev'));
๐ passportConfig ๊ด๋ จ ๋ด์ฉ ์์ฑํ๊ธฐ
โถ passport/index.js
const passport = require('passport');
const local = require('./localStrategy');
const kakao = require('./kakaoStrategy');
const User = require('../models/user');
module.exports = () => {
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findOne({ where: { id } })
.then(user => done(null, user))
.catch(err => done(err));
});
local();
kakao();
};
๐ serializeUser : ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ฒด์์ ์์ด๋๋ฅผ ์ถ๋ ค ์ธ์ ์ ์ ์ฅ
๐ deserializeUser : ์ธ์ ์ ์ ์ฅํ ์์ด๋๋ฅผ ํตํด ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ฒด ๋ถ๋ฌ์ค๊ธฐ
⇒ ์ธ์ ์ ๋๋ฌด ๋ง์ ๋ฐ์ดํฐ๋ฅผ ๋ด์ง ์๊ธฐ ์ํจ
๐ก ์ต์ข ๊ณผ์ : ์ฒซ ๋ก๊ทธ์ธ, ์ธ์ ์์ฑ
1. /auth/login ๋ผ์ฐํฐ๋ฅผ ํตํด ๋ก๊ทธ์ธ ์์ฒญ์ด ๋ค์ด์ด
2. ๋ผ์ฐํฐ์์ passport.authenticate ๋ฉ์๋ ํธ์ถ
3. ๋ก๊ทธ์ธ ๋ก์ง ์ํ
4. ๋ก๊ทธ์ธ ์ฑ๊ณต ์ ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ฒด์ ํจ๊ป req.login ํธ์ถ
5. req.login ๋ฉ์๋๊ฐ passport/serializeUser ํธ์ถ
6. req.session์ ์ฌ์ฉ์ ์์ด๋๋ง ์ ์ฅํด์ ์ธ์ ์์ฑ
7. express-session์ ์ค์ ํ ๋๋ก ๋ธ๋ผ์ฐ์ ์ connect.sid ์ธ์ ์ฟ ํค ์ ์ก
8. ๋ก๊ทธ์ธ ์๋ฃ
๐ก ๋ก๊ทธ์ธ ์ดํ
1. ์ด๋ ํ ์์ฒญ์ด ๋ค์ด์ด
2. ๋ผ์ฐํฐ์ ์์ฒญ์ด ๋๋ฌํ๊ธฐ ์ ์ passport.session ๋ฏธ๋ค์จ์ด๊ฐ passport.deserializeUser ๋ฉ์๋ ํธ์ถ
3. connect.sid ์์ ์ฟ ํค๋ฅผ ์ฝ๊ณ ์ธ์ ๊ฐ์ฒด๋ฅผ ์ฐพ์์ req.session์ผ๋ก ๋ง๋ฆ
4. req.session์ ์ ์ฅ๋ ์์ด๋๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฌ์ฉ์ ์กฐํ
5. ์กฐํ๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ req.user์ ์ ์ฅ(deserializeUser)
6. ๋ผ์ฐํฐ์์ req.user ๊ฐ์ฒด ์ฌ์ฉ ๊ฐ๋ฅ
๐ ๋ก๊ทธ์ธํ ์ฌ์ฉ์ : ํ์ ๊ฐ์
, ๋ก๊ทธ์ธ ๋ผ์ฐํฐ ์ ๊ทผ X
๐ ๋ก๊ทธ์ธํ์ง ์์ ์ฌ์ฉ์ : ๋ก๊ทธ์์ ๋ผ์ฐํฐ ์ ๊ทผ X
⇒ Passport์ req.isAuthenticated ์ฌ์ฉํด ๋ก๊ทธ์ธ ์ฌ๋ถ๋ฅผ ๊ฒ์ฌํ๋ ๋ฏธ๋ค์จ์ด ์์ฑ
โถ middlewares/index.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 {
const message = encodeURIComponent('๋ก๊ทธ์ธํ ์ํ์
๋๋ค.');
res.redirect(`/?error=${message}`);
}
};
๐ ๋ผ์ฐํฐ ์์ฑ
โถ routes/page.js, routes/auth.js
routes/page.js
const express = require('express');
const { isLoggedIn, isNotLoggedIn } = require('../middlewares');
const { renderProfile, renderJoin, renderMain } = require('../controllers/page');
const router = express.Router();
router.use((req, res, next) => {
res.locals.user = req.user;
res.locals.followerCount = 0;
res.locals.followingCount = 0;
res.locals.followingIdList = [];
next();
});
router.get('/profile', isLoggedIn, renderProfile);
router.get('/join', isNotLoggedIn, renderJoin);
router.get('/', renderMain);
module.exports = router;
๐ res.locals.user ์์ฑ์ req.user๋ฅผ ๋ฃ์ด ๋์ ์ค์์ user ๊ฐ์ฒด๋ฅผ ํตํด ์ฌ์ฉ์ ์ ๋ณด์ ์ ๊ทผ
routes/auth.js
const express = require('express');
const passport = require('passport');
const { isLoggedIn, isNotLoggedIn } = require('../middlewares');
const { join, login, logout } = require('../controllers/auth');
const router = express.Router();
// POST /auth/join
router.post('/join', isNotLoggedIn, join);
// POST /auth/login
router.post('/login', isNotLoggedIn, login);
// GET /auth/logout
router.get('/logout', isLoggedIn, logout);
module.exports = router;
๐ ์ปจํธ๋กค๋ฌ ์์ฑ
โถ controllers/auth.js
const bcrypt = require('bcrypt');
const passport = require('passport');
const User = require('../models/user');
exports.join = 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);
await User.create({
email,
nick,
password: hash,
});
return res.redirect('/');
} catch (error) {
console.error(error);
return next(error);
}
}
exports.login = (req, res, next) => {
passport.authenticate('local', (authError, user, info) => {
if (authError) {
console.error(authError);
return next(authError);
}
if (!user) {
return res.redirect(`/?error=${info.message}`);
}
return req.login(user, (loginError) => {
if (loginError) {
console.error(loginError);
return next(loginError);
}
return res.redirect('/');
});
})(req, res, next); // ๋ฏธ๋ค์จ์ด ๋ด์ ๋ฏธ๋ค์จ์ด์๋ (req, res, next)๋ฅผ ๋ถ์
๋๋ค.
};
exports.logout = (req, res) => {
req.logout(() => {
res.redirect('/');
});
};
๐ exports.login
๐ ๋ก๊ทธ์ธ ์ ๋ต ์์ฑ
โถ passport/localStrategy.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');
const User = require('../models/user');
module.exports = () => {
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: false,
}, 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: '๊ฐ์
๋์ง ์์ ํ์์
๋๋ค.' });
}
} catch (error) {
console.error(error);
done(error);
}
}));
};
1. ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ผ์นํ๋ ์ด๋ฏธ์ผ์ด ์๋์ง ๊ฒ์
2. ์๋ค๋ฉด bcrypt์ compare ํจ์๋ก ๋น๋ฐ๋ฒํธ ๋น๊ต
3. ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ๋ค๋ฉด done ํจ์์ ๋ ๋ฒ์งธ ์ธ์๋ก ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฃ์ด ๋ณด๋ด๊ธฐ
4. done์ด ํธ์ถ๋ ํ์๋ ๋ค์ passport.authenticate์ ์ฝ๋ฐฑ ํจ์์์ ๋๋จธ์ง ๋ก์ง์ด ์คํ
5. ๋ก๊ทธ์ธ์ ์ฑ๊ณตํ๋ค๋ฉด ๋ฉ์ธ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ๋๋ฉด์ ๋ก๊ทธ์ธ ํผ ๋์ ํ์ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ค
๐ ์นด์นด์คํก ๋ก๊ทธ์ธ ์ ๋ต ์์ฑ
โถ passport/kakaoStrategy.js
const passport = require('passport');
const KakaoStrategy = require('passport-kakao').Strategy;
const User = require('../models/user');
module.exports = () => {
passport.use(new KakaoStrategy({
clientID: process.env.KAKAO_ID,
callbackURL: '/auth/kakao/callback',
}, async (accessToken, refreshToken, profile, done) => {
console.log('kakao profile', profile);
try {
const exUser = await User.findOne({
where: { snsId: profile.id, provider: 'kakao' },
});
if (exUser) {
done(null, exUser);
} else {
const newUser = await User.create({
email: profile._json?.kakao_account?.email,
nick: profile.displayName,
snsId: profile.id,
provider: 'kakao',
});
done(null, newUser);
}
} catch (error) {
console.error(error);
done(error);
}
}));
};
๐ ์นด์นด์ค ๋ก๊ทธ์ธ ์ค์
๐ ํ์ ๊ฐ์
1. ์นด์นด์ค์์ ์ธ์ฆ ํ callbackURL์ ์ ํ ์ฃผ์๋ก accessToken, refreshToken, profile ์ ์ก
2. profile ๊ฐ์ฒด์์ ์ํ๋ ์ ๋ณด๋ฅผ ๊บผ๋ด์ ํ์ ๊ฐ์
3. ์ฌ์ฉ์๋ฅผ ์์ฑ ํ done ํจ์ ํธ์ถ
๐ ์นด์นด์คํก ๋ผ์ฐํฐ ์์ฑ
โถ routes/auth.js
...
router.get('/logout', isLoggedIn, logout);
// GET /auth/kakao
router.get('/kakao', passport.authenticate('kakao'));
// GET /auth/kakao/callback
router.get('/kakao/callback', passport.authenticate('kakao', {
failureRedirect: '/?error=์นด์นด์ค๋ก๊ทธ์ธ ์คํจ',
}), (req, res) => {
res.redirect('/'); // ์ฑ๊ณต ์์๋ /๋ก ์ด๋
});
module.exports = router;
๐ ์ฝ์ : ํจํค์ง ์ค์น
$ npm i multer
๐ ๋ผ์ฐํฐ ์์ฑ
โถ routes/post.js
const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const { afterUploadImage, uploadPost } = require('../controllers/post');
const { isLoggedIn } = require('../middlewares');
const router = express.Router();
try {
fs.readdirSync('uploads');
} catch (error) {
console.error('uploads ํด๋๊ฐ ์์ด uploads ํด๋๋ฅผ ์์ฑํฉ๋๋ค.');
fs.mkdirSync('uploads');
}
const upload = multer({
storage: multer.diskStorage({
destination(req, file, cb) {
cb(null, 'uploads/');
},
filename(req, file, cb) {
const ext = path.extname(file.originalname);
cb(null, path.basename(file.originalname, ext) + Date.now() + ext);
},
}),
limits: { fileSize: 5 * 1024 * 1024 },
});
// POST /post/img
router.post('/img', isLoggedIn, upload.single('img'), afterUploadImage);
// POST /post
const upload2 = multer();
router.post('/', isLoggedIn, upload2.none(), uploadPost);
module.exports = router;
๐ ์ปจํธ๋กค๋ฌ ์์ฑ
โถ controllers/post.js
const { Post, Hashtag } = require('../models');
exports.afterUploadImage = (req, res) => {
console.log(req.file);
res.json({ url: `/img/${req.file.filename}` });
};
exports.uploadPost = async (req, res, next) => {
try {
const post = await Post.create({
content: req.body.content,
img: req.body.url,
UserId: req.user.id,
});
const hashtags = req.body.content.match(/#[^\s#]*/g);
if (hashtags) {
const result = await Promise.all(
hashtags.map(tag => {
return Hashtag.findOrCreate({
where: { title: tag.slice(1).toLowerCase() },
})
}),
);
await post.addHashtags(result.map(r => r[0]));
}
res.redirect('/');
} catch (error) {
console.error(error);
next(error);
}
};
๐ ๋ฉ์ธ ํ์ด์ง ๋ก๋ฉ ์ ๊ฒ์๊ธ ๋ณด์ฌ์ฃผ๋๋ก ์ปจํธ๋กค๋ฌ ์์
โถ controllers/page.js
const { User, Post } = require('../models');
exports.renderProfile = (req, res) => {
res.render('profile', { title: '๋ด ์ ๋ณด - NodeBird' });
};
exports.renderJoin = (req, res) => {
res.render('join', { title: 'ํ์๊ฐ์
- NodeBird' });
};
exports.renderMain = async (req, res, next) => {
try {
const posts = await Post.findAll({
include: {
model: User,
attributes: ['id', 'nick'],
},
order: [['createdAt', 'DESC']],
});
res.render('main', {
title: 'NodeBird',
twits: posts,
});
} catch (err) {
console.error(err);
next(err);
}
}
๐ ํ๋ก์ ๊ธฐ๋ฅ ์ถ๊ฐ
๐ ์ปจํธ๋กค๋ฌ์ ๋ผ์ฐํฐ ์์ฑ
โถ controllers/user.js , routes/user.js
controllers/user.js
const User = require('../models/user');
exports.follow = async (req, res, next) => {
try {
const user = await User.findOne({ where: { id: req.user.id } });
if (user) { // req.user.id๊ฐ followerId, req.params.id๊ฐ followingId
await user.addFollowing(parseInt(req.params.id, 10));
res.send('success');
} else {
res.status(404).send('no user');
}
} catch (error) {
console.error(error);
next(error);
}
};
routes/user.js
const express = require('express');
const { isLoggedIn } = require('../middlewares');
const { follow } = require('../controllers/user');
const router = express.Router();
// POST /user/:id/follow
router.post('/:id/follow', isLoggedIn, follow);
module.exports = router;
๐ POST /user/:id/folllow : ํ๋ก์ฐํ ์ฌ์ฉ์๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์กฐํํ ํ, ์ํ๋ผ์ด์ฆ์์ ์ถ๊ฐํ addFollowing ๋ฉ์๋๋ก ํ์ฌ ๋ก๊ทธ์ธํ ์ฌ์ฉ์์์ ๊ด๊ณ ์ง์
โญ ํ๋ก์ ๊ด๊ณ๊ฐ ์๊ฒผ์ผ๋ฏ๋ก req.user์๋ ํ๋ก์์ ํ๋ก์ ๋ชฉ๋ก์ ์ ์ฅ
โถ passport/index.js
const passport = require('passport');
const local = require('./localStrategy');
const kakao = require('./kakaoStrategy');
const User = require('../models/user');
module.exports = () => {
passport.serializeUser((user, done) => {
console.log('serialize');
done(null, user.id);
});
passport.deserializeUser((id, done) => {
console.log('deserialize');
User.findOne({
where: { id },
include: [{
model: User,
attributes: ['id', 'nick'],
as: 'Followers',
}, {
model: User,
attributes: ['id', 'nick'],
as: 'Followings',
}],
})
.then(user => {
console.log('user', user);
done(null, user);
})
.catch(err => done(err));
});
local();
kakao();
};
๐ ํด์ํ๊ทธ ๊ฒ์ ๊ธฐ๋ฅ ์ถ๊ฐ
๐ ์ปจํธ๋กค๋ฌ์ ๋ผ์ฐํฐ ์์ฑ
โถ controllers/page.js , routes/page.js
controllers/page.js
const {
renderProfile, renderJoin, renderMain, renderHashtag,
} = require('../controllers/page');
...
router.get('/hashtag', renderHashtag);
routes/page.js
...
exports.renderHashtag = async (req, res, next) => {
const query = req.query.hashtag;
if (!query) {
return res.redirect('/');
}
try {
const hashtag = await Hashtag.findOne({ where: { title: query } });
let posts = [];
if (hashtag) {
posts = await hashtag.getPosts({ include: [{ model: User }] });
}
return res.render('main', {
title: `${query} | NodeBird`,
twits: posts,
});
} catch (error) {
console.error(error);
return next(error);
}
};
[์ถ์ฒ] ์กฐํ์, ใNode.js ๊ต๊ณผ์ใ, ๊ธธ๋ฒ(2020), p417-472
๋น์นธ ์ฑ์ฐ๊ธฐ ๋ฌธ์ (๋น์นธ์ ๋๋๊ทธํด์ ์ ๋ต์ ๋งํ ๋ณด์ธ์!)
module.exports = () => {
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findOne({ where: { id } })
.then(user => done(null, user))
.catch(err => done(err));
});
๐ (serializeUser) : ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ฒด์์ ์์ด๋๋ฅผ ์ถ๋ ค (์ธ์ )์ ์ ์ฅ
๐ (deserializeUser) : ์ธ์ ์ ์ ์ฅํ ์์ด๋๋ฅผ ํตํด ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ฒด ๋ถ๋ฌ์ค๊ธฐ
⇒ (์ธ์
)์ ๋๋ฌด ๋ง์ ๋ฐ์ดํฐ๋ฅผ ๋ด์ง ์๊ธฐ ์ํจ
6. ์ฌ์ง์ด ์ ๋ก๋ ๋ ๊ฒ์๊ธ์ ์ ์ฅํ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ด๋ฏธ์ง (๊ฒฝ๋ก)๊ฐ ์ ์ฅ๋๊ณ , ์ด๋ฏธ์ง๋ (์๋ฒ ๋์คํฌ(uploads ํด๋))์ ์ ์ฅ๋จ
์ฝ๋ ๋ฌธ์
1.
๋ค์์ routes/page.js์ ์ฝ๋ ์ผ๋ถ์ ๋๋ค.
const express = require('express');
const { isLoggedIn, isNotLoggedIn } = require('../middlewares');
const {
renderProfile, renderJoin, renderMain, renderHashtag,
} = require('../controllers/page');
const router = express.Router();
router.use((๋น์นธ1) => {
๋น์นธ2
res.locals.followerCount = req.user?.Followers?.length || 0;
res.locals.followingCount = req.user?.Followings?.length || 0;
res.locals.followingIdList = req.user?.Followings?.map(f => f.id) || [];
next();
});
router.get('/profile', isLoggedIn, renderProfile);
router.get('/join', isNotLoggedIn, renderJoin);
router.get('/', renderMain);
router.get('/hashtag', renderHashtag);
module.exports = router;
tabase, username, password
์ ๋ต
๋น์นธ1 : req, res, next
๋น์นธ 2 : res.locals.user = req.user;
2.
๋ค์์ routes/auth.js์ ์ฝ๋ ์ผ๋ถ์ ๋๋ค.
const express = require('express');
const passport = require('passport');
const { isLoggedIn, isNotLoggedIn } = require('../middlewares');
const { join, login, logout } = require('../controllers/auth');
const router = express.Router();
// POST /auth/join
router.post('/join', ๋น์นธ1, join);
// POST /auth/login
router.post('/login', ๋น์นธ2, login);
// GET /auth/logout
router.get('/logout', ๋น์นธ3, logout);
// GET /auth/kakao
router.get('/kakao', passport.authenticate('kakao'));
// GET /auth/kakao/callback
router.get('/kakao/callback', passport.authenticate('kakao', {
failureRedirect: '/?error=์นด์นด์ค๋ก๊ทธ์ธ ์คํจ',
}), (req, res) => {
res.redirect('/'); // ์ฑ๊ณต ์์๋ /๋ก ์ด๋
});
module.exports = router;
์ ๋ต :
๋น์นธ 1 : isNotLoggedIn
๋น์นธ 2 : isNotLoggedIn
๋น์นธ 3 : isLoggedIn
[๋ ธ๋ 2] 11์ฅ. ๋ ธ๋ ์๋น์ค ํ ์คํธํ๊ธฐ (1) | 2023.12.29 |
---|---|
[๋ ธ๋ 2] 10์ฅ. ์น API ์๋ฒ ๋ง๋ค๊ธฐ (0) | 2023.12.22 |
[๋ ธ๋ 2] 8์ฅ. MongoDB (0) | 2023.11.24 |
[๋ ธ๋ 2] 7์ฅ. MySQL (0) | 2023.11.17 |
[๋ ธ๋ 2] 6์ฅ. ์ต์คํ๋ ์ค ์น ์๋ฒ ๋ง๋ค๊ธฐ (0) | 2023.11.10 |