Node.js에서 JWT(JSON Web Token) 활용하기

조상균·2021년 4월 1일
2

Node.js

목록 보기
1/10
post-thumbnail

앞의 포스팅에서 JWT에 대한 기초적인 내용(https://velog.io/@jguuun/JWTBasic)을 올린 적 있는데, 최근에 Node.js로 JWT인증을 구현해보게 되었고 간략하게 코드를 통해 설명해보려 합니다!


설치

npm init 
npm i jsonwebtoken express

npm을 설정하고 jwt과 express를 설정합니다.


기초 코드

app.js

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
const PORT = 3000;
const KEY = "test_key" // jwt만들 때 시크릿키로 사용
app.get('/', (req, res) => {
	res.sendFile(__dirname + '/index.html'); // 실습을 위한 인덱스 파일
});

/* 이후 코드가 들어갈 자리 */

app.listen(PORT, () => {
	console.log(`Listening at http://localhost:${PORT}`);
});
  • Node.js express서버를 돌리기 위한 기본적인 세팅입니다.
  • express와 jsonwebtoken 모듈을 불러옵니다.

index.html

<button onclick="create_token()">토큰 생성</button>
<button onclick="check_token()">토큰 확인</button>
<button onclick="remove_token()">토큰 삭제</button>

<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
  • 먼저 index.html의 <body>에 생성, 확인, 삭제를 하기 위해 버튼을 각각 생성합니다.
  • 각각의 버튼을 클릭했을 때 실행할 자바스크립트 함수를 적습니다.
  • 뒤에서 기능 구현에서 ajax 호출을 하기 위해 jquery를 불러옵니다.

토큰 생성

app.js

app.get('/sign_token', (req, res) => {
	let token = jwt.sign({ name: 'sancho', exp: parseInt(Date.now()/1000)+10 }, KEY); // 만료기간 10초
	res.json({ token });
});
  • /sign_token 으로 GET요청이 들어왔을 때 토큰을 생성하는 코드입니다.
  • jwt.sign이라는 함수로 name:'sancho'라는 데이터와 만료기간을 10초로 설정하고 KEY(시크릿키)로 암호화하여 토큰을 생성합니다.
  • token은 클라이언트로 반환합니다.

index.html

function create_token() {
  $.ajax({
    type: 'GET',
    url: `/sign_token`,
    success: function (response) {
      const token = response.token;
      document.cookie = `token=${token};path=/`;
      alert("생성 완료!")
    },
    error: function (xhr, textStatus, error) {}
  });
}
  • 토큰 생성 위해 /sign_token의 주소로 GET요청을 보냅니다.
  • 정상적으로 서버가 응답하면 토큰을 쿠키에 담습니다.

토큰 검증

app.js

app.get('/check_token', (req, res) => {
	let token = req.headers['token'];
	try {
		let payload = jwt.verify(token, KEY);
		console.log('토큰 인증 성공', payload)
		res.json({ msg: 'success' });
	} catch (err) {
		console.log("인증 에러");
		res.status(405).json({ msg: 'error' });
		next(err)
	}
});
  • 클라이언트에서 받은 토큰을 검증하는 코드입니다.
  • 헤더에 있는 토큰을 꺼내 jwt.verify 함수로 시크릿키를 활용하여 복호화를 진행합니다.
  • payload에는 name:'sancho'값이 담기게 됩니다.
  • 토큰이 없거나 만료기간이 지났다면 에러이므로 catch에서 인증 에러 메세지를 띄우게 합니다.

index.html

function getCookie(name) {
  let matches = document.cookie.match(new RegExp('(?:^|; )' + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + '=([^;]*)'));
  return matches ? decodeURIComponent(matches[1]) : undefined;
}

function check_token() {
  let token = getCookie('token');
  $.ajax({
    type: 'GET',
    url: `/check_token`,
    headers: {"token":token},
    success: function (response) {
      alert("정상적인 토큰!");
    },
    error: function (xhr, textStatus, error) {
      alert("만료된 토큰!");
    }
  });
}
  • getCookie(쿠키저장소 내 찾을 데이터) 함수를 만듭니다.
  • 쿠키저장소에서 'token'의 데이터를 가져오고 이것을 헤더에 실어 /check_token으로 GET 요청합니다.
  • 정상적으로 서버가 응답하면 정상적임을 알리는 팝업을 띄우고 에러인 경우엔 에러 팝업을 띄웁니다.

토큰 삭제

index.html

function remove_token() {
  document.cookie = `token=;max-age=-1;`;
  alert("토큰 삭제 완료!");
  window.location.reload();
}
  • 토큰은 클라이언트에 있으므로 클라이언트에서 쿠키내의 token을 지우기만 하면 됩니다.
  • 쿠키 유효기간인 max-age의 값을 음수로 하면 쿠키가 바로 지워집니다.

실행

위의 기능을 모두 구현한 모습입니다.


전체 코드

app.js

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
const PORT = 3000;
const KEY = "test_key"
app.get('/', (req, res) => {
	res.sendFile(__dirname + '/index.html');
});

app.get('/sign_token', (req, res) => {
	let token = jwt.sign({ name: 'sancho', exp: parseInt(Date.now()/1000)+10 }, KEY); // 만료기간 10초
	res.json({ token });
});

app.get('/check_token', (req, res) => {
	let token = req.headers['token'];
	try {
		let payload = jwt.verify(token, KEY);
		console.log('토큰 인증 성공', payload)
		res.json({ msg: 'success' });
	} catch (err) {
		console.log("인증 에러");
		res.status(405).json({ msg: 'error' });
		next(err)
	}
});

function errorHandler(err, req, res, next) {
	console.log("에러 처리 핸들러")
}
app.use(errorHandler);

app.listen(PORT, () => {
	console.log(`Listening at http://localhost:/${PORT}`);
});

index.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>토큰 테스트</title>

		<script>
			function create_token() {
				$.ajax({
					type: 'GET',
					url: `/sign_token`,
					success: function (response) {
						const token = response.token;
						document.cookie = `token=${token};path=/`;
						alert("생성 완료!")
					},
					error: function (xhr, textStatus, error) {}
				});
			}

			function getCookie(name) {
				let matches = document.cookie.match(new RegExp('(?:^|; )' + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + '=([^;]*)'));
				return matches ? decodeURIComponent(matches[1]) : undefined;
			}

			function check_token() {
				let token = getCookie('token');
				$.ajax({
					type: 'GET',
					url: `/check_token`,
					headers: {"token":token},
					success: function (response) {
						alert("정상적인 토큰!");
					},
					error: function (xhr, textStatus, error) {
						alert("만료된 토큰!");
					}
				});
			}


			function remove_token() {
				document.cookie = `token=;max-age=-1;`;
				alert("토큰 삭제 완료!");
				window.location.reload();
			}
		</script>
	</head>
	<body>
		<button onclick="create_token()">토큰 생성</button>
		<button onclick="check_token()">토큰 확인</button>
		<button onclick="remove_token()">토큰 삭제</button>
	</body>
	<script
		src="https://code.jquery.com/jquery-3.6.0.js"
		integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
		crossorigin="anonymous"
	></script>
</html>
profile
백엔드 개발을 공부하고 있습니다.

0개의 댓글