[NODE] 노드 jwt 토큰 인증 템플릿!
안녕하세요 :D
오늘은 노드 express를 사용하여 jwt 토큰 인증을 하는 방식과, 기초 세팅해둔 소스파일 공유를 해보려고 합니다.!
평소에 node 환경을 세팅할때 axios, cors, express, dotenv ... 등 설치해야할 패키지가 너무 많습니다.. 매번 세팅하기 귀찮으니 기본적인 패키지 + jwt + mysql 세팅까지 된 템플릿을 만들어 보게 되었습니다.
템플릿을 공유하기 전에! jwt가 뭔지 알아야 사용할 수 있을 것 같아서 간단하게 이야기를 하려 합니다 :D
만약 누구나 API 콜을 칠 수 있다면? 보안상 문제가 있지 않을까..?
만약 로그인한 유저가 장기간 아무 모션을 하지 않을때 로그아웃을 시켜줄 순 없을까..?
개발 초기에 항상 생각하던 내용입니다. api를 만들면서 빠질 수 없는 보안문제를 해결하기 위해 여러가지 방법이 있지만 그 중 한가지가 JWT 입니다.
템플릿 속 JWT의 방식
- 사용자는 로그인을 통해 토큰을 발행한다.
- 헤더를 통해 api 콜 마다 토큰을 전송한다.
- api는 헤더 속 토큰을 검증한 후 유효한지 아닌지를 판단한다.
- 유효하지 않다면 api를 수행하지 않는다.
- 유효하다면 api를 수행한다.
- 헤더는 정해진 유효기간이 종료된 후엔 사용할 수 없다.
그럼 이제 템플릿 속 JWT를 사용하는 방식에 대해 알아보도록 합시다!
const secretKey = process.env.SECRETKEY; // 원하는 시크릿 키
const options = {
algorithm: 'HS256', // 해싱 알고리즘
expiresIn: '30m', // 토큰 유효 기간
issuer: process.env.ISSUER,
};
export { secretKey, options };
secretkey.js 파일은 토큰의 설정을 저장하는 부분입니다. secretkey 부분엔 원하는 시크릿 키를 넣을 수 있는데, 노출되면 안되기 때문에 따로 유출에 유의해야 합니다.
expriresIn은 토큰의 유효기간을 설정하는 부분입니다. default는 30분으로 설정해두었습니다. 너무 짧다고 생각하시거나, 길다고 생각하시면 수정할 수 있습니다 :D
import pkg from 'rand-token';
const { uid } = pkg;
import jwt from 'jsonwebtoken';
const { sign: _sign, verify: _verify } = jwt;
import { secretKey, options } from '../config/secretKey.js';
const TOKEN_EXPIRED = -3;
const TOKEN_INVALID = -2;
export async function sign(user) {
/* 현재는 idx와 email을 payload로 넣었지만 필요한 값을 넣으면 됨! */
const payload = {
user: user,
// idx: user.userIdx,
// email: user.email,
};
const result = {
//sign메소드를 통해 access token 발급!
token: _sign(payload, secretKey, options),
refreshToken: uid(256),
};
return result;
}
export async function verify(token) {
let decoded;
try {
// verify를 통해 값 decode!
decoded = _verify(token, secretKey);
} catch (err) {
if (err.message === 'jwt expired') {
console.log('expired token');
return TOKEN_EXPIRED;
} else if (err.message === 'invalid token') {
console.log('invalid token');
console.log(TOKEN_INVALID);
return TOKEN_INVALID;
} else {
console.log('invalid token');
return TOKEN_INVALID;
}
}
return decoded;
}
중요한 jwt.js 파일입니다. 해당 파일은 토큰 검증 함수 verify와 토큰 발행 함수 sign를 정의하고 있습니다. 토큰을 발행해주는 sign 함수 속 payload에는 원하는 내용을 추가할 수 있습니다. 해당 내용은 토큰을 디코딩했을 때 얻을 수 있는 정보입니다. 여기서는 user만 넣어두었는데, 더 많은 내용을 담을 수 있으니 필요한 정보를 다 담으면 좋겠죠?
검증함수는 간단하게 토큰 만료는 -3을 유효하지 않은 토큰은 -2의 값을 리턴하도록 설정하였습니다.
import { verify } from './jwt.js';
import { response, not_found, bad_response, not_response } from './responseMSG.js';
const TOKEN_EXPIRED = -3;
const TOKEN_INVALID = -2;
const authUtil = {
checkToken: async (req, res, next) => {
var token = req.headers.token;
// 토큰 없음
if (token === undefined) return res.json(await not_response('토큰이 없습니다.'));
// decode
const user = await verify(token);
// 유효기간 만료
if (user === TOKEN_EXPIRED) return res.json(await not_response('유효기간 만료된 토큰'));
// 유효하지 않는 토큰
if (user === TOKEN_INVALID) return res.json(await not_response('유효하지 않은 토큰'));
// req.idx = user.idx;
next();
},
};
export default authUtil;
사용자가 토큰을 넣어 API호출을 시도할 때 거칠 middleware 입니다! checktoken 이란 함수를 통해 토큰을 catch할 것입니다. 토큰을 디코딩하는 jwt.js 파일의 verify 함수를 통해 -3과 -2의 값을 리턴하는지 확인합니다.
문제가 있다면 사용자에게 에러 내용을 response 하게 됩니다. 여기서 모든 res 메세지는 modules/responseMSG.js 에 정의해두었습니다.
JWT를 사용한다면 기본적으로 로그인을 한다는 것으로 생각하고 대충 로그인 관련, 토큰 검증 관련 예제를 만들어 두었습니다. 이해가 가지 않는다면 해당 내용을 통해서도 이해할 수 있을겁니다!
사용하는 방법
- https://github.com/hansolbangul/expressTemplate 에 방문하여 템플릿을 클론 or 다운로드 받습니다. ( 개발자에게 star는 자신감입니다.! 많이 부족하고 별볼일 없지만 한번씩만 눌러주심 감사드리겠습니다. )
- 다운받은 템플릿을 IDE를 통해 열은 후 npm install 을 통해 모든 패키지를 설치해줍니다.
- npm run dev 를 통해 node를 실행시킵니다.
- .env 파일의 내용을 기입합니다.
별건 없는 내용이지만 혹시라도 사용하실 분들 or 제가 사용하기 위해 올려둔 소스입니다! 아직 1년차 신입 개발자라 많이 부족하기 때문에 많은 조언 주신다면 하나하나 적용해 보도록 하겠습니다!!
감사합니다 :D
깃허브 주소 = https://github.com/hansolbangul