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
반응형
'Backend' 카테고리의 다른 글
[Passport.js] Local Strategy에서 username 대신 userId 사용하기 (0) | 2024.07.15 |
---|---|
[Swagger] Default 값, 예시 값 설정하기 (0) | 2024.07.10 |
HTTP 응답 상태 코드(Status Code) (1) | 2024.01.04 |
API(Application Programming Interface) (0) | 2022.11.12 |