Skip to content

Commit

Permalink
fix: refresh token move to cookie
Browse files Browse the repository at this point in the history
  • Loading branch information
ptyoiy committed Jul 17, 2024
1 parent c044f30 commit e225507
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 215 deletions.
8 changes: 3 additions & 5 deletions adminPage/resources/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { COMMON } from './common.js';
import { EVENT } from './event.js';
import { NOTICE } from './notice.js';

export { COMMON, EVENT, NOTICE };
export { COMMON } from './common.js';
export { EVENT } from './event.js';
export { NOTICE } from './notice.js';
53 changes: 6 additions & 47 deletions common_method/index.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,6 @@
import { sendFCM, subscribeTopic, unsubscribeTopic } from './fcmUtils.js';
import {
delEventsPushForBookmarkSchedule,
delEventsPushForEntireSchedule,
setEventsPushForBookmarkSchedule,
setEventsPushForEntireSchedule,
} from './fcm_schedule.js';
import {
delAlertToNoticeSchedule,
delEventToExpiredSchedule,
setAlertToNoticeSchedule,
setEventToExpiredSchedule,
} from './post_schedule.js';
import {
getEventBookmarkInfo,
getEventLikeInfo,
getMajorInfo,
getNoticeLikeInfo,
getNoticeReadInfo,
} from './user_information.js';
import { redisGetAndParse } from './utils.js';
import { IGenericUserRequest, findObjectByPk, findUser, validateRequestBody } from './validator.js';

export {
IGenericUserRequest,
delAlertToNoticeSchedule,
delEventToExpiredSchedule,
delEventsPushForBookmarkSchedule,
delEventsPushForEntireSchedule,
findObjectByPk,
findUser,
getEventBookmarkInfo,
getEventLikeInfo,
getMajorInfo,
getNoticeLikeInfo,
getNoticeReadInfo,
redisGetAndParse,
sendFCM,
setAlertToNoticeSchedule,
setEventToExpiredSchedule,
setEventsPushForBookmarkSchedule,
setEventsPushForEntireSchedule,
subscribeTopic,
unsubscribeTopic,
validateRequestBody
};

export * from './fcm_schedule.js';
export * from './fcmUtils.js';
export * from './post_schedule.js';
export * from './user_information.js';
export * from './utils.js';
export * from './validator.js';
10 changes: 6 additions & 4 deletions controllers/alarm/alarm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ export const setAlarm = async (
// body값이 잘못됐는지 확인
const alarmDataKeys = Object.keys(alarmData);
if (alarmDataKeyList.some((key) => !alarmDataKeys.includes(key))) {
return res.status(401).json({ error: "잘못된 key 입니다." });
throw new Error("잘못된 key 입니다.", {
cause: 401
});
}
const topics = await getTopics(userId, alarmData);

Expand Down Expand Up @@ -65,10 +67,10 @@ export const setAlarm = async (
await transaction.commit();

return res.status(200).json({ message: "알람 설정이 업데이트되었습니다." });
} catch (error) {
} catch (e) {
const error: Error = e;
await transaction.rollback();
console.error(error);
return res.status(500).json({ error });
return res.status(+error.cause || 500).json({ error: error.message });
}
};

Expand Down
149 changes: 81 additions & 68 deletions controllers/jwt/jwt.ts
Original file line number Diff line number Diff line change
@@ -1,93 +1,106 @@
import * as Express from 'express';
import jwt from "jsonwebtoken";
import jwt from 'jsonwebtoken';
import { mode } from '../../adminPage/components/index.js';
import { redisClient } from '../../redis/connect.js';

const ACCESS_EXPIRY = '1d';
const REFRESH_EXPIRY = '7d';

const jwtSecret = process.env.SECRET_KEY;
type Payload = {
id: string;
type: TokenType;
}
id: string;
type: TokenType;
};

enum TokenType {
ACCESS = "ACCESS",
REFRESH = "REFRESH"
ACCESS = 'ACCESS',
REFRESH = 'REFRESH',
}

export const verifyToken = (req: Express.Request, res, next) => {
if (mode == 'development') next();
const token = req.cookies.accessToken;
const id = req.cookies.id;
if (!token) {
return res.status(401).json({
code: 401,
message: '토큰이 제공되지 않았습니다.'
});
}
if (mode == 'development') next();
const accessToken = req.cookies.accessToken;
const refreshToken = req.cookies.refreshToken;
const id = req.cookies.id;
if (!accessToken || !refreshToken) {
return res.status(401).json({
code: 401,
message: '토큰이 제공되지 않았습니다.',
});
}

try {
const payload = jwt.verify(token, process.env.SECRET_KEY) as Payload;
if (payload.id != id) {
throw new Error(`토큰과 다른 사용자. payloadID:${payload.id}, ID:${id}`)
}
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(419).json({ message: '토큰이 만료되었습니다.', error });
}
// TODO: error.message 수정하기
return res.status(401).json({ message: '유효하지 않은 토큰입니다:' + error.message });
try {
const accessPayload = jwt.verify(accessToken, jwtSecret) as Payload;
if (accessPayload.id != id) {
throw new Error(`토큰과 다른 사용자. payloadID:${accessPayload.id}, ID:${id}`);
}
}
const refreshPayload = jwt.verify(refreshToken, jwtSecret) as Payload;
if (refreshPayload.id != id) {
throw new Error(`토큰과 다른 사용자. payloadID:${refreshPayload.id}, ID:${id}`);
}
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(419).json({ message: '토큰이 만료되었습니다.', error });
}
// TODO: error.message 수정하기
return res.status(401).json({ message: '유효하지 않은 토큰입니다:' + error.message });
}
};

export const generate = (id: string) => {
const accessToken = createToken(id, TokenType.ACCESS, ACCESS_EXPIRY);
const refreshToken = createToken(id, TokenType.REFRESH, REFRESH_EXPIRY);
const accessToken = createToken(id, TokenType.ACCESS, ACCESS_EXPIRY);
const refreshToken = createToken(id, TokenType.REFRESH, REFRESH_EXPIRY);

return { accessToken, refreshToken };
}
return { accessToken, refreshToken };
};

const createToken = (id: string, tokenType: TokenType, expiresIn: string): string => {
const payload: Payload = {
id: id.toString(),
type: tokenType,
};
const payload: Payload = {
id: id.toString(),
type: tokenType,
};

return jwt.sign(payload, process.env.SECRET_KEY, { expiresIn });
}

export const reissue = async (refreshToken: string): Promise<{ code: number; message: string; accessToken?: string; id: string}> => {
try {
const decoded = jwt.verify(refreshToken, process.env.SECRET_KEY) as Payload;
return jwt.sign(payload, process.env.SECRET_KEY, { expiresIn });
};

if (decoded.type !== TokenType.REFRESH) {
throw {
code: 500,
message: "refresh 토큰이 유효하지 않습니다"
};
}
export const reissue = async (
refreshToken: string
): Promise<{
code: number;
message: string;
accessToken: string;
refreshToken: string;
id: string;
}> => {
try {
const { type, id } = jwt.verify(refreshToken, process.env.SECRET_KEY) as Payload;

const exists = await redisClient.exists(`refreshToken:${refreshToken}`);

if (!exists) {
throw {
code: 500,
message: "로그인 되지 않은 사용자 입니다."
}
}
if (type !== TokenType.REFRESH) {
throw {
code: 500,
message: 'refresh 토큰이 유효하지 않습니다',
};
}

const id = decoded.id;
const newAccessToken = createToken(id, TokenType.ACCESS, ACCESS_EXPIRY);
const exists = await redisClient.exists(`refreshToken:${refreshToken}`);

return {
code: 200,
message: "새로운 access token이 발급되었습니다.",
accessToken: newAccessToken,
id
};
} catch (error) {
throw error;
if (!exists) {
throw {
code: 500,
message: '로그인 되지 않은 사용자 입니다.',
};
}
}

const gen = generate(id);
await redisClient.del(`refreshToken:${refreshToken}`);
await redisClient.set(`refreshToken:${gen.refreshToken}`, 'true');
return {
code: 200,
message: '새로운 token이 발급되었습니다.',
...gen,
id,
};
} catch (error) {
throw error;
}
};
Loading

0 comments on commit e225507

Please sign in to comment.