yarn add jsonwebtoken
// .env
PORT=4000
MONGO_URI=mongodb://localhost:27017/blog
JWT_SECRET = 만들어진 문자열
...
import jwt from 'jsonwebtoken';
...
UserSchema.methods.generateToken = function() {
const token = jwt.sign(
// 🌟 파라미터1 : 토큰 안에 집어넣고 싶은 데이터
{
_id : this.id,
username : this.username,
},
// 🌟 파라미터2 : JWT 암호
process.env.JWT_SECRET,
// 🌟 파라미터3
{
expiresIn: '7d' // 7일 동안 유효함
},
);
return token;
}
...
export const register = async ctx => {
...
ctx.body = user.serialize();
const token = user.generateToken();
ctx.cookies.set('access_token', token, {
maxAge : 1000 * 60 * 60 * 24 * 7, // 7일
httpOnly : true,
});
} catch (e) {
ctx.throw(500, e);
}
}
export const login = async ctx => {
...
ctx.body = user.serialize();
const token = user.generateToken();
ctx.cookies.set('access_token', token, {
maxAge : 1000 * 60 * 60 * 24 * 7, // 7일
httpOnly : true,
});
} catch (e) {
ctx.throw(500, e)
}
}
...
import jwt from 'jsonwebtoken';
const jwtMiddleware = async (ctx,next) => {
const token = ctx.cookies.get('access_token');
if(!token) return next(); // 토큰이 없음
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
console.log(decoded);
return next();
} catch (e) {
// 토큰 검증 실패
return next();
}
}
export default jwtMiddleware;
// src/main.js
...
import jwtMiddleware from './lib/jwtMiddleware.js';
...
// 라우터 적용 전에 bodyParser 적용
app.use(bodyParser());
// 🌟 라우터 적용 전에 JWT 미들웨어 적용
app.use(jwtMiddleware);
// app 인스턴스에 라우터 적용
app.use(router.routes()).use(router.allowedMethods());
...
// src/lib/jwtMiddleware.js
...
const jwtMiddleware = async (ctx,next) => {
...
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
ctx.state.user = {
_id : decoded._id,
username : decoded.username,
};
console.log(decoded);
return next();
} catch (e) {
...
}
}
...
export const check = async ctx => {
const {user} = ctx.state;
if(!user) {
// 로그인 중이 아님
ctx.status = 401; //Unauthorized
return;
}
ctx.body = user;
}
// src/lib/jwtMiddleware.js
import jwt from 'jsonwebtoken';
import User from '../models/user.js';
const jwtMiddleware = async (ctx,next) => {
...
try {
...
// 토큰의 남은 유효기간이 3.5일 미만이면 재발급
// 🔹 Date.now() 메소드는 UTC 기준으로 1970년 1월 1일 0시 0분 0초부터 현재까지 경과된 밀리초를 반환
const now = Math.floor(Date.now() / 1000);
if(decoded.exp - now < 60 * 60 * 24 * 3.5) {
const user = await User.findById(decoded._id);
const token = user.generateToken();
ctx.cookies.set('access_token', token, {
maxAge : 1000 * 60 * 60 * 24 * 7, // 7일
httpOnly : true,
})
}
return next();
} catch (e) {
// 토큰 검증 실패
return next();
}
}
...
// src/api/auth/auth.ctrl.js
export const logout = async ctx => {
ctx.cookies.set('access_token');
ctx.status = 204; // No Content
}