본문 바로가기
Back-end/Node.js

[Node.js] JWT 토큰으로 인증하기

by 며루치꽃 2021. 6. 14.

전문적인 정보를 다루는 것이 아닌 개인적으로 학습한 내용에 대해

포스팅을 했기 때문에 이점을 감안하여 봐주시면 감사하겠습니다👏

 

코드리뷰 시간에 토큰에 대해 질문을 받았었는데, 프로젝트에 계속 적용하여 사용하는 방법은 알고있었지만,

정확히 개념정리를 해야할 것 같아 정리를 하게 되었습니다. 

 

다른 클라이언트가 데이터를 가져가게 하려면 인증과정이 필요합니다. 이 때 토큰이 필요한데 JWT 토큰으로 알아보려고 합니다. 

JWT는 JSON Web Token의 약어로, JSON 형식의 데이터를 저장하는 토큰입니다. JWT는 다음과 같이 세 부분으로 구성되어 있습니다.

 

  • 헤더(Header) : 토큰 종류와 해시 알고리즘 정보가 들어 있습니다
  • 페이로드(Payload) : 토큰의 내용물이 인코딩된 부분입니다.
  • 시그니처(Signature) : 일련의 문자열이며, 시크니처를 통해 토큰이 변조되었는지 여부를 확인할 수 있습니다. 시그니처는 JWT 비밀키로 만들어지고, 비밀키가 노출되면 토큰 위조가 가능합니다.

JWT는 내용을 볼 수 있기 때문에 민감한 내용을 넣으면 안됩니다.

또한 발급 받은 JWT 토큰을 아래 사이트에서 복호화한 것을 확인할 수 있습니다.

 

JWT 토큰 확인: https://jwt.io/

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

 

Q. 위험해보이는 데도 사용하는 이유?

 

노출이 되는대도 토큰을 사용하는 이유는 내용이 들어있기 때문입니다. 만약 내용이 없는 랜덤한 토큰이 있다고 생각할 때, 랜덤한 토큰을 받으면 토큰의 주인이 누구인지, 그사람의 권한은 무엇인지 매 요청마다 체크해야합니다.

이러한 작업은 보통 데이터베이스를 조회해야 하는 복잡한 작업인 경우가 많습니다.

서버에서 가장 피해야하는 부분이 데이터베이스 조회가 들어간 부분인데, 데이터베이스를 조회하면 데이터베이스에 무리가 가기 때문에 최대한 적게 조회를 해야합니다.

JWT 토큰에는 데이터가 들어있기 때문에 데이터베이스 요청을 줄일 수가 있습니다. 예를 들어, 'kchmin' 이라는 유저가 

있는데, 보통의 경우에는 데이터베이스에 가서 조회를 해야하지만, JWT 토큰만 있다면 JWT 토큰을 믿고 조회를 안하는 것 입니다. 

 

JWT의 또다른 장점은 시그니처에 있습니다. 비밀키가 노출되지 않은 이상, 위조하기가 매우 어렵습니다.

변조한 토큰은 시그니처를 비밀 키를 통해 검사할 때 확인할 수 있기 때문에 사용할 수 있습니다.

JWT 토콘은 외부에 노출되어도 좋은 정보에 한해서 사용해도 됩니다.

 

JWT 토큰 사용하기

 

jsonwebtoken 설치

npm i jsonwebtoken

시그니처에 해당하는 비밀키는 .env에 저장하여 노출하지 않게 해줍니다.

 

.env

JWT_SECRET = jwtSecret

사용하기 위해 미들웨어를 만듭니다.

 

routes / middlewares.js

exports.verifyToken = (req, res, next) => {
  try {
    req.decoded = jwt.verify(req.headers.authorization, process.env.JWT_SECRET);
    return next();
  } catch (error) {
    if (error.name === 'TokenExpiredError') { // 유효기간 초과
      return res.status(419).json({
        code: 419,
        message: '토큰이 만료되었습니다',
      });
    }
    return res.status(401).json({
      code: 401,
      message: '유효하지 않은 토큰입니다',
    });
  }
};

요청 헤더에 저장된 토큰(req.headers.authorization)을 사용합니다. 사용자가 쿠키처럼 헤더에 토큰을 넣어 보냅니다. 

jwt.verify 메서드로 토큰을 검증할 수 있습니다. 메서드의 첫 번째 인수로는 토큰을, 두 번째 인수로는 토큰의 비밀 키를 넣습니다. 

 

토큰의 비밀키가 일치하지 않는다면 인증을 받을 수 없고, 그런 경우에는 에러가 발생하여 catch문으로 가게 됩니다. 또한 토큰에는 유효 기간을 설정할 수 있는데 유효기간이 지난 경우라도 catch문으로 이동하게 됩니다. 

 

인증에 성공한 경우에는 토큰의 내용이 반환되어 req.decoded에 저장됩니다. 토큰의 내용은 민감하지 않는 paylod 등이 들어갑니다. req.decoded를 통해 다음 미들웨어에서 토큰의 내용물을 사용할 수 있습니다. 

 

그리고 이제 토큰을 사용할 때는 아래와 같이 토큰을 발급하여 토큰을 반환해주면 됩니다.

const token = jwt.sign({
      id: domain.User.id,
      nick: domain.User.nick,
    }, process.env.JWT_SECRET, {
      expiresIn: '1m', // 1분
      issuer: 'nodebird',
    });
    return res.json({
      code: 200,
      message: '토큰이 발급되었습니다',
      token,
    });
  • 참고

- zerocho 님의 ' Node.js 교과서'

댓글