본문 바로가기
Backend

JWT

by hyeok1235 2024. 1. 4.

JWT(JSON Web Token)는 인증과 관련된 정보를 JSON 형식으로 저장한 암호화된 웹 토큰입니다.

 

JWT 구조

토큰은 순서대로 header, payload, signature로 구성되어 있습니다. 세 가지 요소는 온점 (”.”)으로 구분되며, 전체적인 형태는 header.payload.signature과 같은 구조를 띄게 됩니다.

  • header : 보통 2가지 정보, 토큰 유형(JWT)과 사용된 서명 알고리즘으로 구성되어 있습니다.
{
"alg": "HS256",
"typ": "JWT"
}
  • payload : 토큰에 저장할 정보들은 이 부분에 들어갑니다.
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
  • signature : header와 payload를 서명한 값을 가지고 있습니다. 서명할 때는 header에 적혀있는 서명 알고리즘과 비밀 키를 사용하기 때문에 무결성을 확인할 수 있습니다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)

 

JWT 장단점

장점

  • 세션을 사용한다면 세션을 위한 별도의 저장소가 필요하지만 JWT는 필요한 정보를 모두 담고 있기 때문에 서버에 저장 공간을 차지하지 않습니다.
  • 확장성 : 토큰 기반으로 하는 다른 인증 시스템들과 연동이 가능합니다. OAuth(ex: 구글, 페이스북)을 사용하는 시스템들과도 호환이 됩니다.

단점

  • 정보를 토큰에 저장하기 때문에 담아야 할 정보가 많아질 수록 통신에 부담이 갈 수 있습니다.
  • Payload는 누구나 디코딩할 수 있기 때문에 중요/민감한 정보는 저장하면 안됩니다.
  • 토큰은 유효기간이 끝날 때까지 누구나 사용할 수 있기 때문에 관리가 잘 안된다면 취약점이 될 수 있습니다.

 

JWT 생성 

다음 코드는 '/signin'에서 로그인을 진행합니다. 26번째 줄에 적혀 있는 부분이 앞서 언급한 signature에 사용되는 비밀 키입니다.

// src/controller/user/controller.ts
const express = require('express');
const passport = require('passport');
const jwt = require('jsonwebtoken');

const router = express.Router();

router.post('/signin',async (req, res, next) => {
try {
// 아까 local로 등록한 인증과정 실행
    passport.authenticate('local', (passportError, user, info) => {
// 인증이 실패했거나 유저 데이터가 없다면 에러 발생
if (passportError || !user) {
        res.status(400).json({ message: info.reason });
return;
      }
// user 데이터를 통해 로그인 진행
      req.login(user, { session: false }, (loginError) => {
if (loginError) {
          res.send(loginError);
return;
        }
// 클라이언트에게 JWT생성 후 반환
const token = jwt.sign(
			{ id: user.id, name: user.name, auth: user.auth },
			'jwt-secret-key'
		);
       res.json({ token });
      });
    })(req, res);
  }catch (error) {
    console.error(error);
    next(error);
  }
});

module.exports = router;

 

 

JWT 검증

다음 코드는 클라이언트가 가지고 있는 JWT를 보고 authentication 과정을 진행해서 로그인을 유지할 수 있게 합니다.

// src/passport/index.js
const passport = require('passport');
const { Strategy: LocalStrategy } = require('passport-local');
const { ExtractJwt, Strategy: JWTStrategy } = require('passport-jwt');
const bcrypt = require('bcrypt');

const User = require('../models/user');

// 중략... (id와 password 확인하는 부분)

const JWTConfig = {
  jwtFromRequest: ExtractJwt.fromHeader('authorization'),
  secretOrKey: 'jwt-secret-key',
};

const JWTVerify =async (jwtPayload, done) => {
try {
// payload의 id값으로 유저의 데이터 조회
const user =await User.findOne({ where: { id: jwtPayload.id } });
// 유저 데이터가 있다면 유저 데이터 객체 전송
if (user) {
      done(null, user);
return;
    }
// 유저 데이터가 없을 경우 에러 표시
    done(null, false, { reason: '올바르지 않은 인증정보 입니다.' });
  } catch (error) {
    console.error(error);
    done(error);
  }
};

module.exports = () => {
  passport.use('local',new LocalStrategy(passportConfig, passportVerify));
  passport.use('jwt',new JWTStrategy(JWTConfig, JWTVerify));
};

 

참고 문서:

 

Passport.js + JWT 로 유저 인증 하기 :: chanyeong

일단 passport와 jwt를 사용하기 전에 이 두가지가 무엇인지부터 알아보도록 하자. JWT란? JWT(JSON Web Token)은 클라이언트와 서버 혹은 서비스간의 통신시 정보를 JSON객체를 통해 안전하게 전송하고 권

chanyeong.com

 

728x90
반응형