import express from 'express'; import cookieParser from 'cookie-parser'; const app = express(); const PORT = 5001; app.use(express.json()); app.use(cookieParser()); // 1. **cookie-parser** ๋ฏธ๋ค์จ์ด๋ฅผ ์ ์ฉํด์ฃผ์ธ์! // 2. `GET` Method๋ก `http://localhost:5001/set`์ ํธ์ถํ์ ๋, **name**์ด๋ผ๋ ์ด๋ฆ์ ๊ฐ์ง โ**nodejsโ** ๋ฌธ์์ด์ ์ ์ฅํ **์ฟ ํค๋ฅผ ๋ฐํ**ํด์ฃผ์ธ์. // 3. `GET` Method๋ก `http://localhost:5001/get`์ ํธ์ถํ์ ๋, ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌ๋ฐ์ ๋ชจ๋ ์ฟ ํค ์ ๋ณด๋ค์ด ๋ฐํ๋๋ API๋ฅผ ๋ง๋ค์ด์ฃผ์ธ์! // ์ฟ ํค ์ด์ฉ app.get('/set', (req, res) => { res.cookie('name', 'nodejs'); //res.cookie๋ฅผ ํตํด ํด๋ผ์ด์ธํธํํ ์ฟ ํค๋ฅผ ์ ๋ฌํ ์ ์์ return res.status(200).end(); }); app.get('/get', (req, res) => { const cookies = req.cookies; console.log(cookies); return res.status(200).json({ cookies }); }); // ์ธ์ ์ด์ฉ (uniqueInt์ ์๊ฐ์ ๋ฃ์ด์ ๊ตฌ๋ถํ๊ธฐ) let session = {}; app.get('/set-session', (req, res) => { const name = '์ค์'; const uniqueInt = Date.now(); session[uniqueInt] = { name }; console.log(session[uniqueInt]); //{ name: '์ค์' } res.cookie('sessionKey', uniqueInt); // sessionKey๋ฅผ ๋ฐ๊ธํ ๊ฑด๋ฐ ๊ทธ ์์ uniqueInt๋ก sessionKey๋ฅผ ์กฐํํ ์ ์์. return res.status(200).end(); }); app.get('/get-session', (req, res) => { const { sessionKey } = req.cookies; console.log(req.cookies); //{ sessionKey: '1699348802445' } console.log(sessionKey); //1699348721612 -> ํ ๋๋ง๋ค ๋ณ๊ฒฝ๋จ console.log(session); //{ '1699348721612': { name: '์ค์' } } const name = session[sessionKey]; console.log(name); //{ name: '์ค์' } return res.status(200).json({ name }); }); app.listen(PORT, () => { console.log(PORT, 'ํฌํธ๋ก ์๋ฒ๊ฐ ์ด๋ ธ์ด์!'); });
EXPRESS-SESSION ์ด์ฉ
์ฟ ํค์ ์ธ์ ์ ์ด์ฉํด์ ๊ทผ๋ณธ์ ์ผ๋ก ์ ๋ ๊ฒ ์ฝ๋๋ฅผ ์งค ์ ์์ง๋ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด์ ๊ฐ๋จํ๊ฒ ์งค ์๋ ์๋ค.
๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น
// express, express-session๋ฅผ ์ค์น yarn add express express-session
// app.js import express from 'express'; import expressSession from 'express-session'; const app = express(); const PORT = 3019; app.use(express.json()); app.use( expressSession({ secret: 'express-session-secret-key.', // ์ธ์ ์ ์ํธํํ๋ ๋น๋ฐ ํค๋ฅผ ์ค์ resave: false, // ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์ฌ ๋๋ง๋ค ์ธ์ ์ ์๋กญ๊ฒ ์ ์ฅํ ์ง ์ค์ , ๋ณ๊ฒฝ์ฌํญ์ด ์์ด๋ ๋ค์ ์ ์ฅ saveUninitialized: false, // ์ธ์ ์ด ์ด๊ธฐํ๋์ง ์์์ ๋ ์ธ์ ์ ์ ์ฅํ ์ง ์ค์ cookie: { // ์ธ์ ์ฟ ํค ์ค์ maxAge: 1000 * 60 * 60 * 24, // ์ฟ ํค์ ๋ง๋ฃ ๊ธฐ๊ฐ์ 1์ผ๋ก ์ค์ ํฉ๋๋ค. }, }), ); app.listen(PORT, () => { console.log(PORT, 'ํฌํธ๋ก ์๋ฒ๊ฐ ์ด๋ ธ์ด์!'); });
/** ์ธ์ ๋ฑ๋ก API **/ app.post('/sessions', (req, res, next) => { const { userId } = req.body; // ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌ๋ฐ์ userId๋ฅผ ์ธ์ ์ ์ ์ฅํฉ๋๋ค. req.session.userId = userId; return res.status(200).json({ message: '์ธ์ ์ ์ค์ ํ์ต๋๋ค.' }); }); /** ์ธ์ ์กฐํ API **/ app.get('/sessions', (req, res, next) => { return res.status(200).json({ message: '์ธ์ ์ ์กฐํํ์ต๋๋ค.', session: req.session.userId ?? null, // ์ธ์ ์ ์ ์ฅ๋ usrId๋ฅผ ์กฐํํฉ๋๋ค. }); });
// ์ธ๋ถ ์ธ์ ์คํ ๋ฆฌ์ง๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ, express-mysql-session ๋ชจ๋์ ์ค์น yarn add express-mysql-session
// src/app.js import express from 'express'; import cookieParser from 'cookie-parser'; import expressSession from 'express-session'; import expressMySQLSession from 'express-mysql-session'; import LogMiddleware from './middlewares/log.middleware.js'; import ErrorHandlingMiddleware from './middlewares/error-handling.middleware.js'; import UsersRouter from './routes/users.router.js'; import PostsRouter from './routes/posts.router.js'; import CommentsRouter from './routes/comments.router.js'; const app = express(); const PORT = 3018; // MySQLStore๋ฅผ Express-Session์ ์ด์ฉํด ์์ฑํฉ๋๋ค. const MySQLStore = expressMySQLSession(expressSession); // MySQLStore๋ฅผ ์ด์ฉํด ์ธ์ ์ธ๋ถ ์คํ ๋ฆฌ์ง๋ฅผ ์ ์ธํฉ๋๋ค. const sessionStore = new MySQLStore({ user: 'root', password: 'aaaa4321', host: 'express-database.clx5rpjtu59t.ap-northeast-2.rds.amazonaws.com', port: 3306, database: 'community_hub', expiration: 1000 * 60 * 60 * 24, // ์ธ์ ์ ๋ง๋ฃ ๊ธฐ๊ฐ์ 1์ผ๋ก ์ค์ ํฉ๋๋ค. createDatabaseTable: true, // ์ธ์ ํ ์ด๋ธ์ ์๋์ผ๋ก ์์ฑํฉ๋๋ค. }); app.use(LogMiddleware); app.use(express.json()); app.use(cookieParser()); app.use( expressSession({ secret: 'customized_secret_key', // ์ธ์ ์ ์ํธํํ๋ ๋น๋ฐ ํค๋ฅผ ์ค์ resave: false, // ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์ฌ ๋๋ง๋ค ์ธ์ ์ ์๋กญ๊ฒ ์ ์ฅํ ์ง ์ค์ , ๋ณ๊ฒฝ์ฌํญ์ด ์์ด๋ ๋ค์ ์ ์ฅ saveUninitialized: false, // ์ธ์ ์ด ์ด๊ธฐํ๋์ง ์์์ ๋ ์ธ์ ์ ์ ์ฅํ ์ง ์ค์ store: sessionStore, // ์ธ๋ถ ์ธ์ ์คํ ๋ฆฌ์ง๋ฅผ MySQLStore๋ก ์ค์ ํฉ๋๋ค. cookie: { // ์ธ์ ์ฟ ํค ์ค์ maxAge: 1000 * 60 * 60 * 24, // ์ฟ ํค์ ๋ง๋ฃ ๊ธฐ๊ฐ์ 1์ผ๋ก ์ค์ ํฉ๋๋ค. }, }), ); app.use('/api', [UsersRouter, PostsRouter, CommentsRouter]); app.use(ErrorHandlingMiddleware); app.listen(PORT, () => { console.log(PORT, 'ํฌํธ๋ก ์๋ฒ๊ฐ ์ด๋ ธ์ด์!'); });
sign ๋ฉ์๋ : jwt ์์ฑ
decode ๋ฉ์๋ : jwt ๋ณตํธํ
verify ๋ฉ์๋ : jwt ๋ณ์กฐ ๊ฒ์ฆ
import jwt from "jsonwebtoken"; const token = jwt.sign({ myPayloadData: 1234 }, "secretKey"); console.log(token); //eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJteVBheWxvYWREYXRhIjoxMjM0LCJpYXQiOjE2OTkzNTQzMTR9.YWfR1LNuKabazvkhWnipzwppNCHGprwlb9oporShoGQ const decodedtoken = jwt.decode(token); console.log(decodedtoken); //{ myPayloadData: 1234, iat: 1699354314 } const decodedValueByVerify1 = jwt.verify(token, "secretKey"); console.log(decodedValueByVerify1); //๋ง๋ค๋ฉด ๋ณตํธํ๋ ๊ฐ ๋ฐํ{ myPayloadData: 1234, iat: 1699354608 } // const decodedValueByVerify2 = jwt.verify(token, "SecretKey"); // console.log(decodedValueByVerify2); //JsonWebTokenError: invalid signature
// app.js import express from 'express'; import jwt from 'jsonwebtoken'; import cookieParser from 'cookie-parser'; const app = express(); const PORT = 3019; const ACCESS_TOKEN_SECRET_KEY = 'Hello'; const REFRESH_TOKEN_SECRET_KEY = 'World'; app.use(express.json()); app.use(cookieParser()); //----------------------------------------------------------- //accessToken, refreshToken ๋ง๋ค๊ธฐ ํจ์ function createAccessToken(id) { return jwt.sign({ id }, ACCESS_TOKEN_SECRET_KEY, { expiresIn: '10s', }); } function createRefreshToken(id) { return jwt.sign({ id }, REFRESH_TOKEN_SECRET_KEY, { expiresIn: '7d', }); } function validateToken(token, secretKey) { try { return jwt.verify(token, secretKey); } catch (error) { return null; } } //-------------------------------------------------- let tokenStorage = {}; //================================================== /** access, refresh token ๋ฐ๊ธ **/ app.post('/tokens', async (req, res) => { const { id } = req.body; const accessToken = createAccessToken(id); const refreshToken = createRefreshToken(id); //refreshToken์ ๊ฐ์ง๊ณ ํด๋น ์ ์ ์ ์ ๋ณด๋ฅผ ์๋ฒ์ ์ ์ฅ tokenStorage[refreshToken] = { id: id, ip: req.ip, userAgent: req.headers['user-agent'], }; // access, refresh Token -> ์ฟ ํค์ ์ ๋ฌ res.cookie('accessToken', accessToken); res.cookie('refreshToken', refreshToken); return res .status(200) .json({ message: 'token์ด ์ ์์ ์ผ๋ก ๋ฐ๊ธ๋์์ต๋๋ค.' }); }); //----------------------------------------------------------- /** accessToken ๊ฒ์ฆ : verify๋ก ๊ฒ์ฆ -> payload๋ก ๋ง๋ค์ด -> id๋ง ์ทจํด -> req.user์ ๋ด๊ธฐ**/ app.get('/tokens/validate', async (req, res) => { const { accessToken } = req.cookies; if (!accessToken) { return res .status(400) .json({ messge: 'Access Token์ด ์กด์ฌํ์ง ์์ต๋๋ค.' }); } const payload = validateToken(accessToken, ACCESS_TOKEN_SECRET_KEY); if (!payload) { return res .status(400) .json({ message: 'Access Token์ด ์ ํจํ์ง ์์ต๋๋ค.' }); } const { id } = payload; return res.status(200).json({ message: `${id}์ payload๋ฅผ ๊ฐ์ง token์ด ์ฑ๊ณต์ ์ผ๋ก ์ธ์ฆ๋์์ต๋๋ค.`, }); }); //----------------------------------------------------------- /** refreshToken์ผ๋ก accessToken ๊ฐฑ์ ํ๊ธฐ : refreshToken ๊ฐ์ ธ์์ -> payload ๋ฝ์๋ด์ refreshtoken์ด ์ ํจํ์ง ํ์ธ -> ์์ฑํ ๋ ๋ง๋ค์ด๋๋ userInfor๋ฅผ ๊ฐ์ ธ์์ ๊ทธ๊ฑธ **/ app.post('/tokens/refresh', async (req, res) => { const { refreshToken } = req.cookies; if (!refreshToken) { return res .status(400) .json({ message: 'Refresh Token์ด ์กด์ฌํ์ง์์ต๋๋ค.' }); } const payload = validateToken(refreshToken, REFRESH_TOKEN_SECRET_KEY); if (!payload) { return res .status(400) .json({ message: 'Refresh Token์ด ์กด์ฌํ์ง์์ต๋๋ค.' }); } const userInfo = tokenStorage[refreshToken]; if (!userInfo) { return res .status(400) .json({ message: 'Refresh Token ์ ๋ณด๊ฐ ์๋ฒ์ ์กด์ฌํ์ง์์ต๋๋ค.' }); } const newAccessToken = createAccessToken(userInfo.id); res.cookie('accessToken', newAccessToken); return res .status(200) .json({ message: 'Access Token์ ์๋กญ๊ฒ ๋ฐ๊ธํ์์ต๋๋ค.' }); }); app.get('/', (req, res) => { return res.status(200).send('Hello Token!'); }); app.listen(PORT, () => { console.log(PORT, 'ํฌํธ๋ก ์๋ฒ๊ฐ ์ด๋ ธ์ด์!'); }); return res .status(200) .json({ message: 'Access Token์ ์๋กญ๊ฒ ๋ฐ๊ธํ์์ต๋๋ค.' }); }); app.get('/', (req, res) => { return res.status(200).send('Hello Token!'); }); app.listen(PORT, () => { console.log(PORT, 'ํฌํธ๋ก ์๋ฒ๊ฐ ์ด๋ ธ์ด์!'); });
๐ post
('/tokens') ์คํํ ๋ชจ์ต : cookies์ accessToken
๊ณผ refreshToken
์ด ์๋ค.
๐ get
('/tokens/validate') ์คํํ ๋ชจ์ต : accessToken
์ ๋ง๋ฃ์๊ฐ(10์ด)๊ฐ ์ง๋์ ์ ํจํ์ง ์๋ค๊ณ ๋์ค๋ ๊ฒ.
๐ get
('/tokens/validate') ์คํํ ๋ชจ์ต :
10์ด ์์ ์คํํ ๋ชจ์ต.
๐ post
('/tokens/refresh') ์คํํ ๋ชจ์ต : accessToken
๊ฐ ๋ง๋ฃ ํ๋ ์ ์ด๋ refreshToken
์ ๋ฐ๊ธํ์ฌ accessToken
๋ฅผ ๊ฐฑ์ ํ ๋ชจ์ต์ด๋ค. ์ฒ์ ๋ฐ๊ธ๋ฐ์์ ๋์ ์๋ก ๊ฐฑ์ ํด์ ๋ฐ์ accessToken
์ ๊ฐ์ด ๋ค๋ฅด๋ค! ์๋๋ฉด jwt์ ๊ตฌ์กฐ ์ค payload์ ๋ด์ฉ ์ค iat (issued at) ๋๋ฌธ์ด๋ค. iat์ ํญ์ ๋ฐ๋๋๋ฐ ์ด๊ฑฐ๋๋ฌธ์ jwt์ ํํ๊ฐ ๊ฐฑ์ ํ ๋๋ง๋ค ๋ฐ๋๋ค.