JWT 인증 미들웨어 구축하기

조성철 (JoSworkS)·2020년 2월 22일
6
post-custom-banner

이번 로그에서는 각 컨트롤러의 api에서 이루어지던 JWT 토큰 인증 과정을 미들웨어로 처리하는 방법에 대해 다뤄보고자 한다.

JWT 인증 미들웨어 개요

JWT 토큰 인증이 필요한 라우터를 위해 JWT 인증을 해당 라우터의 컨트롤러에서 작성하는게 아닌 별도의 커스텀 미들웨어로 만들고 이를 필요한 라우터에 적용하도록 하였다.

미들웨어로 인증이 처리되기 때문에 클라이언트의 요청이 컨트롤러에서 도착하기 전에 커스텀 미들웨어에서 인증과정을 거치게 된다.

JWT 인증 미들웨어 구축

  1. 프로젝트 폴더에 'middleware' 라는 폴더를 만든다. 그리고 그 안에 'authCheker.ts' 라는 커스텀 미들웨어를 만든다.
const token = req.headers.authorization.split('Bearer ')[1];
  1. Request의 header의 Authorization에서 토큰을 추출한다. 여기에서 추출한 Authorization에는 'Bearer'가 포함되어 있기 때문에 Split 메소드를 이용하여 제거한다.

  2. authChecker.ts에 기존 각 컨트롤러에서 처리되던 JWT 인증과정인 jwt.virify(...)를 작성하고 에러가 있는 경우에는 401 상태코드를 클라이언트에 응답하도록 한다.

  3. 반대로 유저의 토큰이 정상적으로 인증되면 next()를 통해 다음 미들웨어로 넘어가게 하도록 한다. (* 이 과정에서 별도의 커스텀 미들웨어가 존재하지 않기 때문에 더 이상 처리될 미들웨어는 존재하지 않는다.)

  4. 이후 각 컨트롤러에 Request가 도착하기 전에 authChecker에 의해 인증절차가 진행되며, 정상적으로 통과한 요청만 각 컨트롤러에서 인증절차가 생략된 상태로 자신의 역할을 수행하게 된다.

// authChecker 예시
// ./src/routes/application.ts
import { Router } from 'express';
import { authChecker } from '../middleware/authChecker';
import * as applicationController from '../controllers/application';
export const applicationRouter = Router();

applicationRouter.post('/', authChecker, applicationController.PostApplication);
applicationRouter.get('/', authChecker, applicationController.GetApplication);
applicationRouter.delete('/', authChecker, applicationController.DeleteApplication);
applicationRouter.put('/', authChecker, applicationController.PutApplication);
applicationRouter.get('/my-application', authChecker, applicationController.GetMyApplication);

결론

JWT 인증 처리를 위해 기존에는 각각의 endpoint 별로 인증 과정에 대한 로직을 작성해야 해서 중복적인 코드가 굉장히 많이 발생하였다. 따라서 불필요한 중복코드를 최소화하고 가독성 있는 코드로 만들기 위해 커스텀 미들웨어로 인증과정을 거치도록 리팩토링 하였고, 이를 통해 코드의 가독성이 훨씬 좋아지는 효과를 거뒀다.

그 전까지는 모듈을 설치하고 index.ts에 모듈의 미들웨어를 설정하는 방식만 사용하였는데, 이처럼 커스텀 미들웨어로 만들어서 클라이언트의 요청을 처리하게 해주었더니 코드 가독성과 로직을 이해하는 데 있어 굉장히 만족감을 느꼈다.

인증과정을 커스텀 미들웨어로 하는 것은 사실 어려운 것은 아니지만, 이와 같이 커스텀 미들웨어를 통해 코드의 퀄리티를 높이는 작업을 많이 해보고 연습하면서 코드의 퀄리티를 높여 나간다는 마음을 잃지 않는게 중요하다고 느꼈다.

소스코드

// ./src/middleware/authChecker.ts
import * as jwt from 'jsonwebtoken';
import jwtObj from '../config/jwt';
import { Request, Response, NextFunction } from 'express';

export const authChecker = (req: Request, res: Response, next: NextFunction) => {
  if (req.headers.authorization) {
    const token = req.headers.authorization.split('Bearer ')[1];

    jwt.verify(token, jwtObj.secret, (err) => {
      if (err) {
        res.status(401).json({ error: 'Auth Error from authChecker' });
      } else {
        next();
      }
    });
  } else {
    res.status(401).json({ error: 'Auth Error from authChecker' });
  }
};

참고자료

post-custom-banner

1개의 댓글

comment-user-thumbnail
2022년 1월 18일

도움이 되었습니다 감사합니다!

답글 달기