Skip to content

Commit

Permalink
Merge pull request #55 from jjikky/feature/auth-redis
Browse files Browse the repository at this point in the history
Feature/auth redis
  • Loading branch information
jjikky authored Jul 13, 2024
2 parents 33ff058 + e9f9733 commit ee24ca7
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 17 deletions.
151 changes: 150 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"pm2": "^5.3.1"
"pm2": "^5.3.1",
"redis": "^4.6.15"
},
"devDependencies": {
"eslint": "^8.57.0",
Expand Down
5 changes: 5 additions & 0 deletions src/common/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ const conf = {

// social login
kakaoRestApiKey: process.env.KAKAO_REST_API_KEY,

redisHost: process.env.REDIS_HOST,
redisPort: process.env.REDIS_PORT,
redisUsername: process.env.REDIS_USERNAME,
redisPassword: process.env.REDIS_PASSWORD,
};

switch (process.env.NODE_ENV) {
Expand Down
3 changes: 2 additions & 1 deletion src/common/constants/error-message.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const ErrorMessage = Object.freeze({
EXIST_EMAIL: '이미 존재하는 이메일 입니다.',
LOGIN_ERROR: '로그인중 오류가 발생하였습니다.',
KAKAO_LOGIN_ERROR: '카카오 로그인중 오류가 발생하였습니다.',
NO_REFRESH_TOKEN: 'refresh token이 존재하지 않습니다.',
NO_REFRESH_TOKEN: '비로그인 상태입니다.',
REFRESH_TOKEN_MISMATCH: '유효하지 않은 Refresh Token입니다.',
REFRESH_TOKEN_ERROR: 'refresh token 검증중 오류가 발생하였습니다.',
DELETE_USER_ERROR: '회원탈퇴중 오류가 발생하였습니다.',

Expand Down
20 changes: 20 additions & 0 deletions src/common/modules/redis/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const conf = require('../../config');
const { createClient } = require('redis');

const redisClient = createClient({
url: `redis://${conf.redisUsername}:${conf.redisPassword}@${conf.redisHost}:${conf.redisPort}/0`,
legacyMode: true, // 레거시 모드를 사용하는 경우에만 설정합니다.
});

redisClient.on('connect', () => {
console.info('✅ Connected to Redis');
});

redisClient.on('error', (err) => {
console.error('Redis Client Error', err);
});

redisClient.connect().then();
const redisCli = redisClient.v4;

module.exports = redisCli;
65 changes: 52 additions & 13 deletions src/routes/user/user.controller.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const passport = require('passport');
const jwt = require('jsonwebtoken');
const config = require('../../common/config');
const redisClient = require('../../common/modules/redis');

const userService = require('./user.service');
const wordService = require('../word/word.service');
Expand Down Expand Up @@ -90,7 +91,7 @@ exports.isEmailExist = async (req, res) => {
exports.localLogin = async (req, res, next) => {
try {
req.body = validateRequest(loginBodySchema, req.body);
passport.authenticate('local', (authError, user, info) => {
passport.authenticate('local', async (authError, user, info) => {
if (authError) {
console.error(authError);
return next(authError);
Expand All @@ -102,6 +103,8 @@ exports.localLogin = async (req, res, next) => {
const accessToken = generateAccessToken(user);
const refreshToken = generateRefreshToken(user);

await redisClient.set(user.email, refreshToken);

res.cookie('refreshToken', refreshToken, config.cookieInRefreshTokenOptions);

return sendResponse.ok(res, {
Expand Down Expand Up @@ -134,6 +137,9 @@ exports.kakaoLogin = async (req, res) => {

const accessToken = generateAccessToken(user);
const refreshToken = generateRefreshToken(user);
console.log(user.email);
const re = await redisClient.set(user.email, refreshToken);
console.log('hh', re);
res.cookie('refreshToken', refreshToken, config.cookieInRefreshTokenOptions);

sendResponse.ok(res, {
Expand All @@ -151,29 +157,52 @@ exports.refreshToken = async (req, res) => {
const refreshToken = req.cookies.refreshToken;
if (!refreshToken) {
// NOTE : 로그인 하지 않은 유저도 refresh token이 없는 경우에 해당하기 때문에, ok로 응답
console.log(ErrorMessage.NO_REFRESH_TOKEN);
return sendResponse.ok(res, {
message: ErrorMessage.NO_REFRESH_TOKEN,
});
}

jwt.verify(refreshToken, config.jwtRefreshSecret, (err, user) => {
jwt.verify(refreshToken, config.jwtRefreshSecret, async (err, user) => {
if (err)
return sendResponse.forbidden(res, {
message: ErrorMessage.REFRESH_TOKEN_ERROR,
});

const newAccessToken = generateAccessToken({ _id: user.userId, nickname: user.nickname, email: user.email });
const newRefreshToken = generateRefreshToken({ _id: user.userId, nickname: user.nickname, email: user.email });
try {
const storedRefreshToken = await redisClient.get(user.email);

res.cookie('refreshToken', newRefreshToken, config.cookieInRefreshTokenOptions);
if (storedRefreshToken !== refreshToken) {
return sendResponse.unAuthorized(res, {
message: ErrorMessage.REFRESH_TOKEN_MISMATCH,
});
}

sendResponse.ok(res, {
message: SuccessMessage.REFRESH_TOKEN,
data: {
accessToken: newAccessToken,
},
});
const newAccessToken = generateAccessToken({
_id: user.userId,
nickname: user.nickname,
email: user.email,
});
const newRefreshToken = generateRefreshToken({
_id: user.userId,
nickname: user.nickname,
email: user.email,
});

await redisClient.set(user.email, newRefreshToken);
res.cookie('refreshToken', newRefreshToken, config.cookieInRefreshTokenOptions);

sendResponse.ok(res, {
message: SuccessMessage.REFRESH_TOKEN,
data: {
accessToken: newAccessToken,
},
});
} catch (error) {
console.error('Redis error:', error);
sendResponse.fail(res, {
message: ErrorMessage.REFRESH_TOKEN_ERROR,
});
}
});
};

Expand All @@ -186,7 +215,17 @@ exports.getProfile = (req, res) => {
});
};

exports.logout = (_, res) => {
exports.logout = async (req, res) => {
const refreshToken = req.cookies.refreshToken;
if (refreshToken) {
try {
const email = req.user.email;
await redisClient.del(email);
} catch (err) {
console.error('Redis error:', err);
}
}

res.clearCookie('refreshToken', config.cookieInRefreshTokenDeleteOptions);
return sendResponse.ok(res, {
message: SuccessMessage.LOGOUT_SUCCESS,
Expand Down
2 changes: 1 addition & 1 deletion src/routes/user/user.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ userRouter.get('/check/email', isEmailExist);
userRouter.post('/local/login', isNotLoggedIn, localLogin);
userRouter.post('/kakao/login', isNotLoggedIn, kakaoLogin);
userRouter.post('/refresh', refreshToken);
userRouter.post('/logout', logout);
userRouter.post('/logout', isLoggedIn, logout);

userRouter.get('/profile', isLoggedIn, getProfile);

Expand Down

0 comments on commit ee24ca7

Please sign in to comment.