TIL

23/11/26 TIL __ passport ๋กœ ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ 1

GABOJOK 2023. 11. 26. 23:57

 

 

๐Ÿž๏ธ ์ƒํ™ฉ

 

๋‚˜๋Š” ์‚ฌ์‹ค ์•„์ฃผ ์˜ˆ์ „๋ถ€ํ„ฐ

์นด์นด์˜คํ†ก ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๊ณผ ๊ฐ™์€ ์†Œ์…œ ๋กœ๊ทธ์ธ๊ธฐ๋Šฅ์„ ๊ผญ ํ•ด๋ณด๊ณ  ์‹ถ์—ˆ๋‹ค. 

์‚ฌ์šฉ์ž๋กœ์„œ๋„ ๋„ˆ๋ฌด ํŽธ๋ฆฌํ•œ ๊ธฐ๋Šฅ์ด์˜€๊ณ , 

์•ž์œผ๋กœ๋„ ๋งŽ์ด ๊ตฌํ˜„ํ•˜๊ฒŒ ๋  ๊ธฐ๋Šฅ ๊ฐ™์•„ ํ•„์ˆ˜์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

 

๋ฌผ๋ก  ๊ทธ ์ „์— ๊ธฐ์ดˆ์ ์ธ ์ฟ ํ‚ค, ํ† ํฐ, ์„ธ์…˜, refreshToken  ๋“ฑ๋“ฑ์„ ์•Œ์•„์•ผ ํ–ˆ์ง€๋งŒ,

์ฝ”๋”ฉ์„ ์ฒ˜์Œ ์‹œ์ž‘ํ•˜๋˜ ๊ทธ๋•Œ์—๋Š” ๊ฒ์ด ์—†์—ˆ๊ณ , ์ผ๋‹จ ์‚ฌ์ดํŠธ์—์„œ ๋’ค์ ธ๋ดค์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ทธ ๋‹น์‹œ์—๋Š” ๊ธฐ์ดˆ์ง€์‹์ด ๋ถ€์กฑํ•ด ์ž˜ ์•Œ์•„๋“ฃ์ง€ ๋ชปํ–ˆ๊ณ , ๊ฒฐ๊ตญ ๋ชปํ–ˆ๋‹ค.

 

๋ถ€ํŠธ์บ ํ”„๋ฅผ ํ†ตํ•ด ๊ณต๋ถ€ํ•˜๋ฉด์„œ, ์ธ์ฆ ์ธ๊ฐ€์™€ ๊ฐ™์€ ๊ฐœ๋…๋“ค์„ ๋ฐฐ์šฐ๊ณ  ๋‚˜๋‹ˆ,

์ด์ œ ์ง„์งœ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•˜๋‹ค. 

๊ทธ๋ž˜์„œ ํŒ€ํ”„๋กœ์ ํŠธ ํ•„์ˆ˜๊ธฐ๋Šฅ์€ ๋ชจ๋‘ ๊ตฌํ˜„์„ ํ•œ ๋’ค์—,

๋ฐค์„ ์ƒˆ๋ฉด์„œ๋ผ๋„ ๊ตฌํ˜„์„ ํ•ด์•ผ๊ฒ ๋‹ค ๋งˆ์Œ ๋จน์—ˆ๋‹ค. 

 

 

์ผ๋‹จ ์ง€๊ธˆ๊นŒ์ง€ ์ •๋ฆฌ๋œ ๋‚ด์šฉ์„ ์ ์–ด๋ณด๊ฒ ๋‹ค. 

๊ณต๋ถ€๋Š” ์ƒํ™œ์ฝ”๋”ฉ๋‹˜ ๊ฐ•์˜์™€, 

์ธํŒŒ๋‹˜ ๋ธ”๋กœ๊ทธ ๋ฐ ๋‹ค๋ฅธ ๋งŽ์€ ๋ธ”๋กœ๊ทธ๋ฅผ ๋ณด์•˜๋‹ค. 

 

 


 

๐Ÿฃ  passport 

  • ์ธ์ฆ ๋ฐ ์ธ๊ฐ€ ์ž‘์—…์— ์žˆ์–ด์„œ ์ข€๋” ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ๋ชจ๋“ˆ์ด๋‹ค.
  • ์†Œ์…œ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ• ๋•Œ ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค.
  • passport ์—๋Š” 2๊ฐ€์ง€ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.  ๋กœ์ปฌ ๋ฐฉ์‹, ์†Œ์…œ๋กœ๊ทธ์ธ ๋ฐฉ์‹.

 

๋‚˜์˜ ๊ฒฝ์šฐ ์†Œ์…œ๋กœ๊ทธ์ธ์„ ์œ„ํ•ด passport๋ฅผ ๋„์ž…ํ•œ ๊ฒƒ์ž„์œผ๋กœ, ๋กœ์ปฌ๋ฐฉ์‹์€ ์ง€๋‚˜๊ฐ€๊ฒ ๋‹ค.

์ผ๋‹จ 4๊ฐœ์˜ ํŒŒ์ผ์„ ๋งŒ๋“ค์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ธฐ์กด์— ์žˆ๋˜ app.js ํŒŒ์ผ์—๋„ ์ฝ”๋“œ๋“ค์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. 

 

์ผ๋‹จ app.js์— ์ถ”๊ฐ€ํ•œ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค. 

const passport = require('passport');
const kakaoStrategy = require('passport-kakao').Strategy;
const passportConfig = require('./passport');
const session = require('express-session');

passportConfig();

app.use(
	session({
		resave: false,
		satisfies: false,
		secret: process.env.COOKIE_SECRET,
		cookie: {
			httpOnly: true,
			secure: false,
		},
	}),
);

app.use(passport.initialize()); //req์— passport์„ค์ • ์‹ฌ์Œ.
app.use(passport.session()); //req์— passport ์ •๋ณด ์ €์žฅ.


app.use('/api', [
	authRouter,
	UsersRouter,
	PostsRouter,
	CommentsRouter,
]);

 

 

์นด์นด์˜ค ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๋„ฃ๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์—ˆ๋˜ ํŒŒ์ผ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. 

 

passport ๋ผ๋Š” ํŒŒ์ผ ์•ˆ์— 

     index.js

     kakaoStrategy.js

 

routers ํŒŒ์ผ ์•ˆ์—

     auth.js 

 

 

์ผ๋‹จ routers/auth.js ํŒŒ์ผ ๋จผ์ € ๋ณด๊ฒ ๋‹ค.

require('dotenv').config();

const express = require('express');
const passport = require('passport');
const router = express.Router();
const jwt = require('jsonwebtoken');

//์ด ์ฃผ์†Œ๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด authenticate ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. 
//๊ทธ๋Ÿผ kakaoStrategy๋กœ ์ด๋™ํ•ด ์ „๋žต์„ ์‹คํ–‰ํ•œ๋‹ค. 
//์นด์นด์˜ค ๋กœ๊ทธ์ธ์—์„œ๋Š” ์นด์นด์˜ค ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•œ๋‹ค. 
router.get('/kakao', passport.authenticate('kakao'));

//์นด์นด์˜ค ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์—์„œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์นด์นด์˜ค์—์„œ ์„ค์ •ํ•œ redirect uri๋กœ ์ด๋™ํ•œ๋‹ค. 
router.get(
	'/kakao/callback',
	passport.authenticate('kakao', {
    	//ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๊ฐ€ ์‹คํŒจ๋ผ๋ฉด ์•„๋ž˜์˜ ๊ฒฝ๋กœ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ํ•œ๋‹ค. 
		failureRedirect: '/api/login',
	}),
    //ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๊ฐ€ ์„ฑ๊ณต์ด๋ผ๋ฉด ์•„๋ž˜ ์ผ๋ จ์˜ ๊ณผ์ •์„ ์ฒ˜๋ฆฌํ•œ๋‹ค. 
	async (req, res) => {
		const userId = req.user.dataValues.id;
		const token = jwt.sign(
			{ userId: userId },
			process.env.SECRET_KEY,
			{
				expiresIn: '12h',
			},
		);
		res.cookie('Authorization', `Bearer ${token}`);
		res.locals.user = { userId: req.user.dataValues.id };
		res.redirect('/api/main');
	},
);

module.exports = router;

 

 

 

 

๋‹ค์Œ์œผ๋กœ authenticate๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด์„œ ์‹คํ–‰๋˜๋Š” 

kakaoStrategy.js ํŒŒ์ผ์„ ์‚ดํŽด๋ณด๊ฒ ๋‹ค.

require('dotenv').config();

const passport = require('passport');
const kakaoStrategy = require('passport-kakao').Strategy;
const bcrypt = require('bcrypt');

const { Users } = require('../models');

const kakaoLogin = () => {
    passport.use(
        new kakaoStrategy(
            {
                clientID: process.env.KAKAO_ID,
                callbackURL: '/api/kakao/callback',
            },
            async (accessToken, refreshToken, profile, done) => {
                try {
                    const exUser = await Users.findOne({
                        where: { email: profile._json.kakao_account.email },
                    });

                    const hashPwd = await bcrypt.hash('profile.id', 11);
                    
                    //ํšŒ์›๊ฐ€์ž…์ด ๋˜์–ด์žˆ๋Š” ๊ฒฝ์šฐ
                    if (exUser) {
                    	//์ด done์ด ์‹คํ–‰๋˜๋ฉด์„œ, routers/auth.js ํŒŒ์ผ์˜ authentication ๋‚ด๋ถ€์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
                        //๋˜ํ•œ done() ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜๊ธด ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋„˜์–ด๊ฐ„ ํŒŒ์ผ์—์„œ ๋ฐ›๋Š”๋‹ค. 
                        done(null, exUser);
                    } else {
                        //ํšŒ์›์ด ์•„๋‹Œ๊ฒฝ์šฐ ํšŒ์›๊ฐ€์ž… ์‹œํ‚ค๊ธฐ
                        const newUser = await Users.create({
                            email: profile._json.kakao_account.email,
                            name: profile.displayName,
                            password: hashPwd, //์ˆ˜์ •
                            provider: 'kakao',
                        });
                        done(null, newUser);
                    }
                } catch (err) {
                    //๊ทธ์™ธ ์—๋Ÿฌ ๋ฐœ์ƒ์‹œ ์—๋Ÿฌ ์ „๋‹ฌ.               	
                    done(err);
                }
            },
        ),
    );
};

module.exports = kakaoLogin;

 

 

 

์ธํŒŒ๋‹˜ ๋ธ”๋กœ๊ทธ๋กœ ์•Œ๊ฒŒ๋œ ์‚ฌ์‹ค์ธ๋ฐ,  done ํ•จ์ˆ˜์˜ ์ธ์ž๊ฐ’์ด ์•„๋ž˜์™€ ๊ฐ™์€ ์—ญํ• ์„ ํ•œ๋‹ค๋Š” ๊ฑธ ์•Œ๋ฉด ์ข€๋” ์ดํ•ด๊ฐ€ ์‰ฌ์› ๋‹ค. 

//๋กœ๊ทธ์ธ์ด ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ
                              done(null,  exUser)
passport.authenticate('kakao', (authError, user, info)=>{})


//๋กœ๊ทธ์ธ์ด ์‹คํŒจํ•œ ๊ฒฝ์šฐ
                              done(null,   false,  [message: ])
passport.authenticate('kakao', (authError, user, info)=>{})


//์„œ๋ฒ„ ์—๋Ÿฌ๋‚œ ๊ฒฝ์šฐ
                              done(error)
passport.authenticate('kakao', (authError, user, info)=>{})

 

 

 

 

 

๋‹ค์Œ์€ passport/index.js ํŒŒ์ผ์ด๋‹ค. 

const passport = require('passport');
const kakao = require('./kakaoStrategy.js');

const { Users } = require('../models');

module.exports = () => {
	//req.session ๊ฐ์ฒด์— ๋ฐ์ดํ„ฐ ์ €์žฅ.
	passport.serializeUser((user, done) => {
		done(null, user.id);
	});
    //์„œ๋ฒ„ ์š”์ฒญ์ด ์˜ฌ๋•Œ๋งˆ๋‹ค ํ•ญ์‚ด ์‹คํ–‰๋˜๋ฉฐ, req.user์— ์ €์žฅํ•œ๋‹ค. 
	passport.deserializeUser((id, done) => {
    	//์œ ์ € ์•„์ด๋””๋ฅผ ํ…Œ์ด๋ธ”์—์„œ ์ฐพ์€ ๊ฒฝ์šฐ, ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ ๋˜ ํ•จ์ˆ˜ ์‹คํ–‰.
		Users.findOne({ where: { id } }).then(user => done(null, user));
	});

	kakao();
};

 

 

 

 

๐Ÿงก  ๋Š๋‚€์ 

์ด๋Ÿฐ์‹์œผ๋กœ ๋ธ”๋กœ๊ทธ๋“ค์„ ๋”ฐ๋ผ๊ฐ€๋‹ค ๋ณด๋‹ˆ

๋“œ๋””์–ด ์นด์นด์˜คํ†ก ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ๊ตฌํ˜„์— ์„ฑ๊ณตํ•˜์˜€๋‹ค!!

๋„ˆ๋ฌด ๊ธฐ๋ถ„์ด ์ข‹์•˜์ง€๋งŒ, passport์— ๋Œ€ํ•ด ์ •๋ง ์ž˜ ์•Œ๊ณ  ์žˆ๋‹ˆ? ๋ผ๊ณ  ๋ฌผ์–ด๋ณธ๋‹ค๋ฉด ๋…ธ! ํ• ๊บผ ๊ฐ™๋‹ค..

์•„์ง์€ ์ข€๋” ๋ณด๊ณ , ๋งŒ์ ธ๋ด์•ผ ๋‚ด๊ฒƒ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค. 

์–ด์จ‹๋˜ ๊ณผ์ œ ์ œ์ถœ ์ „์— ๊ตฌํ˜„ํ•ด์„œ ์ •๋ง ๋‹คํ–‰์ด๋‹ค.