[Node.js] CH3 개인과제 - 미들웨어 구현

GDORI·2024년 9월 12일
0

Node.js

목록 보기
11/11

구현한 미들웨어 목록

  • 토큰 인증 미들웨어
  • 에러핸들링 미들웨어
  • 에러로그 미들웨어 ( /utils/CustomErr 포함 )
  • 캐릭터 소유권 검증 미들웨어

토큰 인증 미들웨어

로그인 시 헤더에 반환된 토큰을 기준으로 JWT 인증이 필요한 라우트에서 request.header에 authorization이 있는지 확인 후
검증한다.

토큰이 없을 경우, Bearer 형식이 아닌경우, 페이로드에 담긴 유저 정보가 없는 토큰일 경우에는 에러를 발생시킨다.


export default async function (req, res, next) {
  try {
    const { authorization } = req.headers; // 헤더에서 토큰 정보 추출

    if (!authorization)
      // 토큰이 없을 시 에러
      throw new CustomErr("요청한 사용자의 토큰이 없습니다.", 404);

    const [tokenType, token] = authorization.split(" "); // 토큰 형식과 데이터 분리
    if (tokenType !== "Bearer")
      // 베어러 타입이 아닐경우 에러
      throw new CustomErr("토큰 타입이 Bearer 형식이 아닙니다.", 400);

    const decodedToken = jwt.verify(token, SECRET_CODE); // 토큰 디코딩
    const userId = decodedToken.userId; // 디코딩한 토큰의 페이로드 내 유저ID 삽입

    const user = await prisma.users.findFirst({
      where: { userId: userId },
    });
    // 해당하는 유저가 없을 시 에러
    if (!user) throw new CustomErr("토큰 사용자가 존재하지 않습니다.", 404);

    req.user = user; // request에 user 객체 설정
    next(); // 다음 미들웨어로 전달
  } catch (err) {
    return res.status(400).json({ message: err.message });
  }
}

캐릭터 소유권 검증 미들웨어

특정 라우터에서 중복된 부분이 있어 미들웨어로 만들어 추가해주었다.

인증 미들웨어를 거친 후 user 객체와 캐릭터 번호로 character 테이블에서 조회를 하고 있을 경우 character 객체로 다음 미들웨어로 전달해주고 아니면 에러를 반환.

export default async function (req, _, next) {
  try {
    // 인증 미들웨어에서 생성한 user와 URL 매개변수에서 추출
    const {
      user: { userNo },
      params: { characterNo },
    } = req;

    const character = await prisma.characters.findFirst({
      where: { characterNo: +characterNo }, // characterNo 와 일치한 데이터 요청
    });
    if (!character)
      throw new CustomErr("캐릭터가 정보가 존재하지 않습니다.", 404); // 캐릭터 객체가 없을 시 에러
    if (character.userNo !== userNo)
      throw new CustomErr("캐릭터 접근 권한이 없습니다.", 401); // 캐릭터 소유권자와 토큰 인증자가 다를 시 에러
    req.character = character; // request에 캐릭터 객체 설정
    next();
  } catch (err) {
    return res.status(400).json({ message: err.message });
  }
}

에러핸들링/ 에러 로그 미들웨어

커스텀 에러 클래스를 생성하여 에러를 throw할 때 에러 정보와
status code를 받아 처리하는 미들웨어를 만들었다.

try-catch 구문을 통해 에러 부분을 customErr로 throw 해주면, catch는 에러 미들웨어로 정보를 넘긴다.
에러 미들웨어에서는 해당 에러 내용을 처리한다.

에러로그 미들웨어는 에러가 생겼을 경우 로그를 터미널에 출력한다.

  • CustomErr Class
  constructor(message, statusCode) {
    super(message); // Error 클래스의 message 속성 설정
    this.statusCode = statusCode; // 추가적인 statusCode 속성 설정
  }
  • error 핸들링 미들웨어
export default function (err, req, res, next) {
  // statusCode 가 전달되지 않은 경우 지정 외 에러이므로 500 할당
  const statusCode = err.statusCode || 500;
  // 서버 에러 출력
  console.error(err);

  if (statusCode === 500)
    res.status(500).json({ errorMessage: "서버 내부 에러가 발생했습니다." });

  // 클라이언트에게 에러 메시지를 전달
  res.status(statusCode).json({
    errorMessage: err.message,
    statusCode: statusCode,
  });
}
  • error log 미들웨어

// winston 설정에서 로그 레벨을 error로 설정
const logger = winston.createLogger({
  level: "error", // error 로그만 출력
  format: winston.format.json(),
  transports: [
    new winston.transports.Console({
      level: "error",
    }),
  ],
});

export default function (req, res, next) {
  const start = new Date().getTime();

  res.on("finish", () => {
    // 응답속도 계산
    const duration = new Date().getTime() - start;

    if (res.statusCode >= 400) {
      // 오류 상태 코드일 경우 error 레벨로 로그
      logger.error(
        `Method: ${req.method}, URL: ${req.url}, Status: ${res.statusCode}, Duration: ${duration}ms`
      );
    }
  });
  next();
}
profile
하루 최소 1시간이라도 공부하자..

0개의 댓글