authorization을 구현할 수 있는 방법으로 Session과 Token을 포스팅 한 적이 있습니다.
( https://velog.io/@yebb/Authorization-Session-vs-Token)
오늘은 프로젝트에서 어떻게 JWT를 사용해볼 수 있을지 정리해보려 합니다..
아래 명령어로 프로젝트에 jsonwebtoken을 설치합시다 :
npm install jsonwebtoken
token을 sign하려면 3가지 정보가 필요합니다.
1. secret key
2. token으로 해싱할 data
3. token 만료시간
주의 :
secret key가 너무 심플하면 token verification 프로세스를 분해하는데 너무 쉬워질 위험이 있다.
따라서,
- Node.js의 built-in 라이브러리인
cypto
같은 것을 이용해서 secret key를 생성하는 것도 방법이며- 혹은 secret key 생성해주는 사이트도 있음.
e.g) https://www.lastpass.com/features/password-generator
이제, secret key를 프로젝트의 .env
파일에 저장합시다. :
TOKEN_SECRET=09f26e402586e2faa8da4c98a35f1b20d6b033c60... //예시를 위한 임의의 secret key값
주의 :
secret key가 노출되면 안되므로.env
파일은 깃헙에 올라가지 않도록
.gitignore
파일에도 추가해주자.
Node.js파일에 token을 가져와 사용하기 위해선 dotenv
를 사용해야 합니다..
dotenv
도 설치해주자
npm install dotenv
그 다음 아래와 같이 파일에 import 해주자 :
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';
//get config vars
dotenv.config();
// access config var
process.env.TOKEN_SECRET;
token에 해싱할 데이터는 user ID 나 username 또는 더 복잡한 object같은 것이 될 수도 있으나 어떤 경우이든 해싱할 데이터는 특정 user를 식별할 수 있는 식별자여야 합니다.
주의 : 디코딩하면 노출되므로 사용자의 민감한 정보는 담지 말아야!
token 만료시간은 string으로 1800초(30분) 같은 값이 들어가는데 여기에 얼마나 token을 유효하게 할 것인지 지정합니다.
function generateAccessToken(username) {
return jwt.sign(username, process.env.TOKEN_SECRET, { expiresIn: '1800s' });
}
이는 user의 회원가입이나 로그인 요청에서 쓰일 수 있습니다. :
app.post('/api/createNewUser', (req,res) => {
//...
//token생성하여 응답으로 보내기
const token = generateAccessToken({username:req.body.username});
res.json(token);
//...
});
위 예시에서 request
로 username
을 받아 token
을 만들어 response
를 보냈습니다.
Express.js 어플리케이션에서 JWT authentication을 구현하는 방법은 매우 다양합니다.
한가지 방법은 Express.js의 middleware기능을 활용하는 것입니다.
특정 route에 request가 왔을 때 app.get((req,res)=>{})에 지정된 것보다 먼저 중개 역할을 하는 function에서 req,res변수를 전달할 수 있습니다.
middleware는 function으로 (req,res,next) parameters를 가집니다.
req
: GET, POST, PUT, DELETE 등으로 보내진 request.res
: 다양한 방식으로 user에게 다시 보내질 response.res.sendStatus(200)
, res.json()
등)next
: next는 middleware의 실행을 지나 실제 app.get
서버 응답으로 전해지도록 호출되는 function입니다.여기 authentication을 위한 middleware의 예시 입니다. :
import jwt from 'jsonwebtoken';
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401)
//token 검증
jwt.verify(token, process.env.TOKEN_SECRET as string, (err: any, user: any) => {
console.log(err)
if (err) return res.sendStatus(403)
req.user = user
next()
})
}
이 middleware function을 사용하는 request의 예시는 다음과 같은 형태입니다. :
GET https://example.com:4000/api/userOrders
Authorization: Bearer JWT_ACCESS_TOKEN
그리고 middleware를 사용하는 request의 예는 다음과 같습니다.
app.get('/api/userOrders', authenticateToken, (req, res) => {
// executes after authenticateToken
// ...
});
이 코드는 client가 전달한 token을 인증하는 코드입니다.
만약 token이 유효하다면, request를 계속할 수 있고
그렇지 않다면, error로 처리될 것입니다.
client가 token을 받게 되었을 때, 미래의 request에서 user 정보를 수집하기 위해 token을 저장해두기도 합니다.
auth token을 저장하는 가장 대중적인 방법은 HttpOnly
cookie에 저장하는 것 입니다.
client측 js code를 사용해 cookie 저장을 구현해 보았습니다. :
// get token from fetch request
const token = await res.json();
// set token in cookie
document.cookie = `token=${token}`
이는 미래에 서버로 request를 보낼 수 있도록 참조할 수 있는 곳에 local하게 response를 저장해두는 방식입니다.
참고
https://www.digitalocean.com/community/tutorials/nodejs-jwt-expressjs