[2019.05.10] JWT-Token 방식의 정보 인증 [사용법]
사용자가 로그인 후, 유저 정보를 cookie,Session 방식이 아닌 token 방식으로 안전하게 관리하는 방법이 있다.
# token 방식의 특징
- 사용자 정보를 일일히 서버의 세션에 저장하지 않고, 사용자의 로컬에 저장.
- 사용자가 요청을 보낼 때마다 유저 정보 확인을 일일히 하지 않아도 됨.
- 웹 표준 기반 기술로써, 여러 환경에서 지원
이러한 토큰 방식을 사용하기 위해서는 JWT(Json Web Token) 기술을 사용한다.
# JWT 모듈 설치법
npm i -D jsonwebtoken
모듈을 설치한다.
# token 생성법
토큰을 생성하는 방법은 아래와 같다.
const jwt = require('jsonwebtoken');
var userInfo = {id: 1, username: 'inyong'};
var secretKey = 'SeCrEtKeYfOrHaShInG';
var 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번째 인자의 콜백함수로 받을 수 있으므로 넣어준 함수.
그럼 서버에서 사용자에게 요청을 받았을 시, token을 사용자에게 전달해주는 코드를 작성해보자.
예시)
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
})
});
var server = app.listen(3000, function(){
console.log("Express server has started on port 3000");
});
jwt.sign()함수는 비동기 함수이므로 Promise 처리를 해줘야 한다. 하단 부분에 res.send()로 사용자에게 토큰을 보내준다.
postMan을 이용해서 서버에게 요청을 보내보고, 응답으로 받은 토큰 값을 확인해보자.
JWT 홈페이지에서, 서버에게 받은 token값을 이용하여 인코딩 및 디코딩을 해볼 수 있다. token으로 나온 값을 Encoded 입력박스에 넣어보면, sign으로 넣었던 user 정보 및 options가 나오는 것을 확인할 수 있다.
# token 검증 방법
사용자는 서버에게서 토큰을 받은 후, 서버에게 요청을 보낼 때, 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 함수
예시)
client
var 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 단 서버 요청
server
//생략
...
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 관리도 더 잘 될 것 같다.
벨로퍼트님 강의가 정말 많은 도움이 되고 있다....