JWT 토큰 [ node.js ] [ express ]

2023. 7. 16. 14:48node.js

JWT 토큰이란?

 

Json 포멧을 이용해 사용자에 대한 속성을 저장하는 웹 토큰이다.

JWT 는 토큰 자체를 정보로 사용한다. 주로 회원 인증이나 정보 전달에 사용된다.

 


JWT 구조

 

JWT 는 Header, Payload, Signature 의 세가지 부분으로 이루어 지고,

Json 형태인 각 부분은 Base64Url 로 인코딩 되어 표현된다.

또 각 부분을 이어주기 위해서 . 구분자를 사용하여 구분한다.

 

* Base64Url 은 암호화된 문자열이 아니고 같은 문자열에 대해 항상 같은 인코딩 문자열을 반환한다.

 

 

 

1. Header(헤더)

 

토큰의 헤더는 typ 과 alg 두 가지 정보로 구성된다.

{ 
   "alg": "HS256",
   "typ": JWT
}

typ : 토큰의 타입을 지정 ex) JWT

alg : 알고리즘 방식을 지정하며, 서명 및 토큰 검증에 사용된다. ex) HS256, RSA

 

2. PayLoad (페이로드)

 

토큰의 페이로드에는 토큰에서 사용할 정보의 조각들인 클레임(Claim) 이 담겨있다.

클레임은 총 3가지 이며 key/value 형태로 다수의 정보를 넣을 수 있다.

 

3. Signature (서명)

 

토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드.

서명을 위해서 만든 헤더와 페이로드의 값을 각각 BASE64Url 로 인코딩 하고, 인코딩한 값을 비밀 키를 이용해 헤더에서 정의한 알고리즘으로 해싱하고 이 값을 다시 BASE64Url 로 인코딩하여 생성한다.

 


고려사항

 

- 토큰 자체에 정보를 담고 있어 양날의 검이 될 수 있다.

 

- 토큰이 페이로드에 3종류의 클레임을 저장하기 때문에 정보가 많아질 수록 토큰의 길이가 늘어나 네트워크 부하를 줄 수 있다.

 

- 페이로드 자체는 암호화 된 것이 아니라, BASE64Url 로 인코딩 된 것이다. 중간에 페이로드를 탈취하여 디코딩 당하면 데이터를 볼 수 있으므로 암호화하거나 페이로드에 중요 데이터를 넣지 않아야 한다.

 

- JWT 는 상태를 저장하지 않기 때문에 한번 만들어지면 제어가 불가능하므로, 토큰을 임의로 삭제하는 것이 불가능해 토큰 만료 시간을 꼭 넣어주어야 한다.

 

- 토큰은 클라이언트 측에서 관리해야 하기 때문에 토큰을 저장해야 한다.

 

 


 

코드 예시

 

 

npm i jsonwebtoken

login.controller.js

// ...
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");

// ...

refreshToken = []

// ...

const { nickname, password } = req.body;

const user = await this.loginService.loginUser(nickname);
const validPassword = await bcrypt.compare(password, user.password);

const token = jwt.sign({ nickname }, 'jwt_secret', {
expiresIn: "1h",
});

const refreshToken = jwt.sign(
{ nickname },
'jwt_refresh_secret',
{
  expiresIn: "14d",
}
);
this.refreshTokens.push(refreshToken);

res.cookie("Authorization", `Bearer ${token}`);
res.cookie("RefreshToken", refreshToken);

return res.status(200).json({ token: token });

// ...

 

auth-middleware.js

 

const jwt = require("jsonwebtoken");
const { Users } = require("../models");

require("dotenv").config();

const generateAccessToken = (nickname) => {
  console.log("accessToken 재생성");
  const accessToken = jwt.sign({ nickname }, process.env.JWT_SECRET, {
    expiresIn: "1h",
  });
  return accessToken;
};

module.exports = async (req, res, next) => {
  try {
    const { Authorization, RefreshToken } = req.cookies;

    const [type, token] = (Authorization ?? "").split(" ");

    if (!type || type !== "Bearer" || !token) {
      return res
        .status(403)
        .json({ errorMessage: "로그인이 필요한 기능입니다." });
    }

    const decodeToken = jwt.verify(token, process.env.JWT_SECRET, {
      ignoreExpiration: true, // 만료 여부 검사를 무시
      //ignoreExpiration 옵션을 true로 설정하여 만료 여부 검사를 무시합니다. 만료된 경우에도 검사를 통과한다.
    });
    const nickname = decodeToken.nickname;

    const findUser = await Users.findOne({ where: { nickname } });
    if (!findUser) {
      return res
        .status(403)
        .json({ errorMessage: "로그인이 필요한 기능입니다." });
    }

    res.locals.user = findUser;

    // Refresh Token 유효성 검사
    if (!RefreshToken) {
      return res
        .status(403)
        .json({ errorMessage: "로그인이 필요한 기능입니다." });
    }

    const decodeRefreshToken = jwt.verify(
      RefreshToken,
      process.env.JWT_REFRESH_SECRET
    );
    const refreshNickname = decodeRefreshToken.nickname;
    if (nickname !== refreshNickname) {
      return res.status(403).json({
        errorMessage:
          "Refresh Token과 Access Token의 사용자가 일치하지 않습니다.",
      });
    }

    // Access Token이 만료되었을 경우 재발급
    const newAccessToken = generateAccessToken(nickname);
    res.setHeader("Authorization", `Bearer ${newAccessToken}`);

    next();
  } catch (err) {
    console.error(err);
    return res
      .status(403)
      .json({ errorMessage: "전달된 쿠키에서 오류가 발생했습니다." });
  }
};

 

 

그냥 서버 배열에 refreshtoken 을 저장했지만 실제 환경에서는 redis 에 저장해야 할 것 같음.

 

 

 

 


https://mangkyu.tistory.com/56

 

[Server] JWT(Json Web Token)란?

현대 웹서비스에서는 토큰을 사용하여 사용자들의 인증 작업을 처리하는 것이 가장 좋은 방법이다. 이번에는 토큰 기반의 인증 시스템에서 주로 사용하는 JWT(Json Web Token)에 대해 알아보도록 하

mangkyu.tistory.com

 

'node.js' 카테고리의 다른 글

에러처리 미들웨어 [ express ] [ node.js ]  (0) 2023.07.22
multer  (0) 2023.07.20
bcrypt 사용방법 [ Javascript ] [ node.js ]  (0) 2023.07.07
PM2 사용  (0) 2023.06.24
노드 내장 객체 : global [ node.js 교과서 ]  (0) 2023.04.10