const jwt = require('jsonwebtoken');
let userInfo = {id: 1, username: 'inyong'};
let secretKey = 'SeCrEtKeYfOrHaShInG';
let options = {expiresIn: '7d', issuer: 'inyongTest', subject: 'userInfo'};
jwt.sign(userInfo, secretKey, options,
function(err,token){
if(err) console.log(err);
else console.log(token); // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJpbnlvbmciLCJpYXQiOjE1NTc0ODc2MjIsImV4cCI6MTU1ODA5MjQyMiwiaXNzIjoiaW55b25nVGVzdCIsInN1YiI6InVzZXJJbmZvIn0.idVKe2FVsmvwYBPFJc9vMXi4eZRfFJ6rwhiHIY4gZeo
}
)
jwt.sign() 함수에 들어가는 4가지 인자 설명
userInfo : 아이디, 비밀번호 등 사용자 정보가 들어간 object이다. 형식은 상관없음.
secretKey : 여러가지 복잡한 문자열로 되어있는 키.
options: 토큰에 대한 여러가지 정보를 설정한다. expiresIn은 토큰 만료일, issuer, subject는 토큰에 대한 정보이다. 외에도 options가 더 있다.
4번째 인자로 들어가는 익명함수 : token 생성결과를 4번째 인자의 콜백함수로 받을 수 있으므로 넣어준 함수.
const express = require("express");
const jwt = require('jsonwebtoken');
const app = express();
app.get('/',(req, res)=>{
const getToken = () => {
return new Promise((resolve, reject) => {
jwt.sign(
{
id: 1,
username: 'inyong' // 유저 정보
},
'SeCrEtKeYfOrHaShInG', // secrec Key
{
expiresIn: '7d',
issuer: 'inyongTest', // options
subject: 'userInfo'
},
function(err,token){
if(err) reject(err) // callback
else resolve(token)
}
)
});
}
getToken().then(token =>{
res.send(token); // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJpbnlvbmciLCJpYXQiOjE1NTc0ODc2MjIsImV4cCI6MTU1ODA5MjQyMiwiaXNzIjoiaW55b25nVGVzdCIsInN1YiI6InVzZXJJbmZvIn0.idVKe2FVsmvwYBPFJc9vMXi4eZRfFJ6rwhiHIY4gZeo
})
});
let server = app.listen(3000, function(){
console.log("Express server has started on port 3000");
});
jwt.sign()함수는 비동기 함수이므로 Promise 처리를 해줘야 한다. 하단 부분에 res.send()로 사용자에게 토큰을 보내준다.
사용자는 서버에게서 토큰을 받은 후, 서버에게 요청을 보낼 때, request.Header에 토큰을 포함하여 요청을 보낸다.
그러면 서버는 사용자에게서 받은 토큰이 유효한 것인지 확인한다.
const secretKey = ''; // 아까 token 만들때 썼던 secretkey
const router = (req, res) => {
const token = req.headers['x-access-token'] || req.query.token;
jwt.verify(token, secretKey,
function(err, decoded){
console.log(err) // 유효하지 않은 토큰
console.log(decoded) // 유효한 토큰, 유저 정보 Object 반환
}
}
jwt.verify()함수를 이용하여 토큰 유효성을 확인할 수 있다.
jwt.verify() 함수에 들어가는 매개변수 3개
token: client에게서 받은 token
secretkey : token 생성 시 사용했던 secretKey
3번째 인자로 들어간 익명함수 : 유효성 검사 결과를 처리할 callback 함수
예시)
let token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJpbnlvbmciLCJpYXQiOjE1NTc0OTE3NTYsImV4cCI6MTU1ODA5NjU1NiwiaXNzIjoiaW55b25nVGVzdCIsInN1YiI6InVzZXJJbmZvIn0.fpLkn6R6zjJXFq0i9xWpSmLrYmo-afyBjbPg2fJM25s';
fetch('http://localhost:3000', {
method: 'POST',
body: JSON.stringify({name:'inyong'}),
headers: {
'content-type': 'text/json',
'x-access-token': token
}
})
.then(res => {return res.json()})
.then(res => {
this.render(res);
});
// client 단 서버 요청
//생략
...
const router = (req, res, next) => {
const token = req.headers['x-access-token'] || req.query.token; // client에게서 받은 토큰
/* 토큰이 없으면 403 에러 응답 처리 */
if(!token){
return res.status(403).json({
success: false,
message: 'not logged in'
});
}
/* 토큰 유효성 검사 */
const p = new Promise((resolve, reject) => {
jwt.verify(token, req.app.get('jwt-secret'), (err,decoded) => {
if(err) reject(err);
else resolve(decoded);
})
});
/* 유효하지 않은 토큰으로 403 에러 처리 */
const onError = (error) => {
res.status(403).json({
success: false,
message: error.message
})
};
p.then((decoded)=>{
res.json(decoded);
}).catch(onError);
}
app.post('/decoded', router);
참고로 secret 키와 토큰 검증 부분은 요청시 계속 사용되는 부분이다.
secret키는 .config파일로 따로 빼고, 토큰 검증 함수는 미들웨어로 빼서 사용하면 쉽게 사용할 수 있다.
앞으로 정보 관리방식은 JWT방식으로 처리하는 방식으로 쓰면 될 것 같다.
cookie와 Session 방식의 로그인 정보 인증을 해보지는 않았지만, 굳이 JWT 방식을 놔두고 써 볼 일은 없을 것 같다. 확실히 JWT 방식의 장점이 더 많고, Session 관리도 더 잘 될 것 같다.
findOne 공부하기