JWT은 JSON 형태를 이용해 사용자의 정보를 저장하는 클레임(Claim) 기반의 Web Token이다.

 

JWT는 3가지의 정보를 가진 구조로 되어있다.

 

#1. Header(헤더)

#2. Payload(페이로드)

#3. Signature(서명)

 

각각의 구조의 대해 간단히 설명 하자면 

 

Header(헤더)에는 typ과 alg의 데이터 정보가 들어가있는데 이것은 Signature(서명)에 사용될 알고리즘이 들어가 있다.

Payload(페이로드)에는 Access Token 발행시 사용될 정보들이 들어가 있으면 JSON 형태로 이루어져 있다.

Signature(서명)에는 토큰을 복호화 하거나 유효성 검사를 할 때 사용되는 고유 난수값이 들어가 있다.

 

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

 

에서 JWT를 디코딩 하면서 해당 구조를 확인 할수있다.

 

JWT의 로직의 관련된 부분은 여타 다른 매체에서 훨씬 자세하게 나와있다. (유튜브, 블로그 등)

 

간단하게 이야기하자면 

 

#1. 클라이언트가 서버에서 발급받은 Secret Code와 특정 데이터(로그인 정보 등)를 가지고 서버에 Access Token을 요청한다.

#2. 서버에서는 해당 사용자가 정상적인가를 체크하고 Secret Code와 암호화 방식을 가지고 클라이언트에게 Access TokenRefresh Token을 준다.

(이 때 해당 Access Token의 유효 기간도 함께 주는것이 보안상 안전하다 이를 위해 필요한것이 Refresh Token)

#3. 클라이언트에서는 다시 서버로 부터 발급받은 Access Token을 헤더에 넣고 다시 서버에게 정보를 요청한다.

#4. 서버에서는 클라이언트의 요청의 들어가있는 Access Token과 데이터의 유효성을 체크하고 원하는 정보를 제공한다.

#5. 이때 클라이언트가 가진 Access Token의 유효시간이 다 끝났으면 Refresh Token을 통해 다시 Access Token을 요청한다.

#6. 이후 반복

 

최근 여러사이트에서 거의 필수적으로 사용된는 Oauth2 또한 이러한 방식으로 진행된다.

 


 

그럼 이제 node.js를 통해 JWT를 사용해 보자.

// setup
npm init -y
npm i dotenv express jsonwebtoken
npm i nodemon --save-dev

 

JWT를 테스트 하기 위해 필요한 npm module를 설치해주고 module를 import 해주고 세팅 해준다.

// import
require('dotenv').config();
const express = require('express');
const app = express();
const jwt = require('jsonwebtoken');

// middleware
app.use(express.json());

// sample data
const dataList = [
 {
   username: 'User1',
   data: 'Data 1'
 },
 {
   username: 'User2',
   data: 'Data 2'
 }
]

 

그다음에 테스트를 위해 난수를 만들고 .env파일에 저장해둔다. (.env는 환경변수 파일)

 // create random text
 node
 require('crypto').randomBytes(64).toString('hex')
 // 3cc38ecfc28adf2b04fe62852cc24ee7648cc4898c42c90d8ecb6e77e426806ba62bfebf11b7c1a4de5e5bcfe40a8f0f484ba8ae58077eb765230736b9f14da6
 
 // .env file
 ACCESS_TOKEN_SECRET=3cc38ecfc28adf2b04fe62852cc24ee7648cc4898c42c90d8ecb6e77e426806ba62bfebf11b7c1a4de5e5bcfe40a8f0f484ba8ae58077eb765230736b9f14da6
 PORT=3000

 

이제 Secret Code를 통해 Access Token을 발급 받아보자.

// get data
app.get('/datas', checkAccessToken, (req, res) => {
  res.json(dataList.filter(data => data.username === req.user.name));
});

// login
app.post('/login', (req, res) => {
  // Authenticate User
  const username = req.body.username;
  const user = { name: username };
  const accessToken = createAccessToken(user);
  
  res.json({ accessToken: accessToken });
});

function createAccessToken(user) {
  return jwt.sign(user, process.env.ACCESS_TOKEN_SECRET);
};

function checkAccessToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];
  if (token == null) return res.sendStatus(401);

  jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
    console.log(err);
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
};

app.listen(process.env.PORT, () => {
  console.log(`Server listening on port ${process.env.PORT}`);
});

 

#1. /login endpoint에 post 방식으로 user데이터 값을 던진다.

#2. backend에서는 전달받은 user데이터의 유효성을 검사하고 같이 가지고 있는 Secret Code와 함께 Access Token을 생성한다.

(지금은 expire가 없다. 추후글에 포스팅 예정)

#3. 이후에 클라이언트 쪽에서 /datas endpoint에 get방식으로 데이터를 요청한다.

(이때 Header에 authorization: "Bearer 발급받은 Access Token"를 넣어서 보낸다.)

#4. backend에서는 클라이언트에서 요청한 데이터가 유효한지 체크하고 데이터를 넘겨준다.

 


 

GET http://localhost:3000/datas
authorization: "Bearer Access Token"

###

POST http://localhost:3000/login
Content-Type: application/json

{
  "username": "User2"
}

'Node & AWS > Node' 카테고리의 다른 글

eslint, prettier, eslint-config-airbnb #2  (0) 2022.10.09
eslint, prettier, eslint-config-airbnb #1  (0) 2022.10.09
socket.io (WebSocket)  (0) 2022.10.03
process.env 환경변수 (environment)  (0) 2022.09.22
http module #0  (0) 2022.01.18