[NodeJS] JWT 생성 및 검증

seonjeong·2023년 6월 24일

NodeJS

목록 보기
14/19
post-thumbnail

💖 JWT (JSON Web Token)

  • 웹에서 사용되는 JSON 형식의 토큰에 대한 표준 규격
  • 주로 사용자의 인증(authentication) 또는 인가(authorization) 정보를 서버와 클라이언트 간에 안전하게 주고 받기 위해서 사용

인증과 인가

인증(authentication) : 말그대로 인증하는 것, 로그인
인가(authorization) : 인증을 받은 사용자가 서비스를 이용하려할 때 허가해주는 것

🔥 구조

헤더(header)와 페이로드(payload), 서명(signature) 3부분으로 이루어 졌으며 각각의 부분은 인코딩 혹은 암호화가 되어 있다.

[header].[payload].[signature]
  • Base64로 인코딩된 문자열
  • 토큰 타입, 서명 알고리즘 2부분으로 이루어짐
{
  "alg": "HS256",	// 알고리즘, 서명 값을 만드는 데 사용될 알고리즘이 저장됨
  "typ": "JWT"	// 타입, 고정값
}

Payload

  • Base64로 인코딩된 문자열
  • 사용자 정보 등의 데이터가 담긴 claim이 포함되어 있는 부분
    ex ) 사용자의 식별자(ID), 이름, 이메일 주소, 역할 등
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Signature

  • 인코딩된 헤더, 인코딩된 페이로드, 비밀 키, 헤더에 지정된 알고리즘을 사용하여 서명 값 생성
  • 서명은 메시지가 변경되지 않았음을 확인하기 위해 사용되며 개인 키로 서명된 토큰의 경우 JWT의 발송자를 학인할 수 있음
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

🔥 장단점

장점

  • 상태를 유지하지 않아(Stateless), 확장성 있는(Scalable) 애플리케이션 구현 용이함
  • 인증에 필요한 모든 정보를 담고 있기 때문에 인증을 위한 별도의 저장소가 필요 없음
  • 여러 서비스 간에 토큰을 교환하기 쉬움

단점

  • 토큰의 길이가 길어, 인증 요청이 많아질수록 네트워크 부하가 심해짐
  • Payload의 디코딩이 용이하여 저장된 데이터에 누구나 쉽게 열람이 가능함
  • 특정 토큰을 강제로 만료시키기가 어려움 -> 토큰이 탈취당할 경우 대처가 어려움

💖 JWT 생성 및 검증

🔥 설치

npm install jsonwebtoken

🔥 생성

jwt.sign(payload, secretOrPrivateKey, [options, callback])

예시

토큰 생성 유틸리티

import jwt from "jsonwebtoken";

export class GenerateTokenUtil {
  private secretKey: string;

  constructor(secretKey: string) {
    this.secretKey = secretKey;
  }

  public generateToken(id: number, nickname: string, expiresIn: string) {
    const payload = {
      id: id,
      nickname: nickname,
    };

    const token = jwt.sign(payload, this.secretKey, { expiresIn: expiresIn });
    return token;
  }
}

🔥 검증

jwt.verify(token, secretOrPublicKey, [options, callback])

예시

발급된 토큰을 검증하는 미들웨어

export const tokenValidator = (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  const authorizationHeader = req.headers.authorization;

  if (authorizationHeader && authorizationHeader.startsWith("Bearer ")) {
    const token = authorizationHeader.slice(7); // "Bearer " 부분을 제외한 나머지 문자열을 추출

    try {
      const decodedToken = jwt.verify(token, process.env.SECRET_KEY!);
      req.decoded = decodedToken; // 토큰의 복호화된 데이터 저장
      next(); // 다음 미들웨어로 이동
    } catch (error) {
      console.log(error);
      throw new CustomError("유효하지 않은 토큰입니다.", HttpCode.UNAUTHORIZED);
    }
  } else {
    throw new CustomError("토큰이 존재하지 않습니다.", HttpCode.NOT_FOUND);
  }
};




Reference

https://jwt.io/introduction
https://www.daleseo.com/jwt/
https://www.npmjs.com/package/jsonwebtoken

profile
🦋개발 공부 기록🦋

0개의 댓글