카테고리 없음

nodejs에서 JWT 토큰 사용하기

쿠와와 2021. 1. 9. 19:09

여기서 JWT는 욕아님 

 

인증을 위한 JWT(JSON Web Token)

 

밑에의 페이지에서 소스의 정보를 확인할 수 있음

jwt.io/

NodeBird가 아닌 다른 클라이언트가 데이터를 가져가게 하려면 인증 과정이 필요함

  • JWT(JSON Web Token)을 사용함 
  • 헤더.페이로드.시그니처로 구성됨
  • 헤더: 토큰 종류와 해시 알고리즘 정보가 들어있음
  • 페이로드: 토큰의 내용물이 인코딩된 부분
  • 시그니처: 일련의 문자열로, 시그니처를 통해 토큰이 변조되었는지 여부 확인
  • 시그니처는 JWT 비밀키로 만들어지고, 비밀키가 노출되면 토큰 위조 가능

 

JWT 사용 시 주의점

 

JWT에 민감한 내용을 넣으면 안 됨

  • 페이로드 내용 볼 수 있음

  • 그럼에도 사용하는 이유는 토큰 변조가 불가능하고, 내용물이 들어있기 때문
  • 내용물이 들어있으므로 데이터베이스 조회를 하지 않을 수 있음(데이터베이스 조회는 비용이 큰 작업)
  • 노출되어도 좋은 정보만 넣어야 함
  • 용량이 커서 요청 시 데이터 양이 증가한다는 단점이 있음
  • 위에 코드로 보면 ey~FQ까지는 볼 수 있어도 . 뒤에 나오는 비밀키는 유출되면 안됨

 

 

 

노드에서 JWT 사용하기

 

JWT 모듈 설치

  • npm i jsonwebtoken
  • JWT 비밀키 .env에 저장
  • JWT 토큰을 검사하는 verifyToken 미들웨어 작성
  • jwt.verify 메서드로 검사 가능(두 번째 인수가 JWT 비밀키)
  • JWT 토큰은 req.headers.authorization에 들어 있음
  • 만료된 JWT 토큰인 경우 419 에러 발생
  • 유효하지 않은 토큰인 경우 401에러 발생
  • req.decoded에 페이로드를 넣어 다음 미들웨어에서 쓸 수 있게 함
const jwt = require('jsonwebtoken');

exports.isLoggedIn = (req, res, next) => {
  if (req.isAuthenticated()) {
    next();
  } else {
    res.status(403).send('로그인 필요');
  }
};

exports.isNotLoggedIn = (req, res, next) => {
  if (!req.isAuthenticated()) {
    next();
  } else {
    res.redirect('/');
  }
};

exports.verifyToken = (req, res, next) => {
  try {
    req.decoded = jwt.verify(req.headers.authorization, process.env.JWT_SECRET);
    return next();
  } catch (error) {
    if (error.name === 'TokenExpiredError') { // 유효기간 초과
      return res.status(419).json({
        code: 419,
        message: '토큰이 만료되었습니다',
      });
    }
    return res.status(401).json({
      code: 401,
      message: '유효하지 않은 토큰입니다',
    });
  }
};

 

JWT 토큰 발급 라우터 만들기

routes/v1.js 작성

  • 버전 1이라는 뜻의 v1.js
  • 한 번 버전이 정해진 후에는 라우터를 함부로 수정하면 안 됨
  • 다른 사람이 기존 API를 쓰고 있기 때문(그 사람에게 영향이 감)
  • 수정 사항이 생기면 버전을 올려야 함
  • POST /token에서 JWT 토큰 발급
  • 먼저 도메인 검사 후 등록된 도메인이면 jwt.sign 메서드로 JWT 토큰 발급
  • 첫 번째 인수로 페이로드를 넣고, 두 번째 인수는 JWT 비밀키, 세 번째 인수로 토큰 옵션(expiresIn은 만료 시간, issuer발급자)
  • expiresIn1m(1), 60 * 1000같은 밀리초 단위도 가능
  • GET /test 라우터에서 토큰 인증 테스트 가능
  • 라우터의 응답은 일정한 형식으로 해야 사용자들이 헷갈리지 않음

 

 

 

 

app.js에 라우터 연결

.
.
.
.
const dotenv = require('dotenv');

dotenv.config();
const v1 = require('./routes/v1');
const authRouter = require('./routes/auth');
.
.
.
app.use(passport.session());

app.use('/v1', v1);
app.use('/auth', authRouter);
.
.
.

 

 

JWT 토큰으로 로그인하기

세션 쿠키 발급 대신 JWT 토큰을 쿠키로 발급하면 됨

  • Authenticate 메서드의 두 번째 인수로 옵션을 주면 세션 사용하지 않음

클라이언트에서 JWT를 사용하고 싶다면

  • process.env.JWT_SECRET은 클라이언트에서 노출되면 안 됨
  • RSA같은 양방향 비대칭 암호화 알고리즘을 사용해야 함
  • JWTPEM 키를 사용해서 양방향 암호화를 하는 것을 지원함