Application Programming Interface
다른 프로그램에서 활용할 수 있게 허용하는 접점.
서버가 다른 사람에게 제공해주고 싶은 정보를 API로 열어놓은 것
토큰인증과, 사용량 제한 등의 방식으로 제공량과 대상을 제어할 수 있다.
서버에 부담을 많이 주는 크롤링을 막기 위해서도 공개해도 되는 정보에 대해서 API를 제공해 주면 좋다.
일반적인 express 서버구조와 크게 다르지 않음.
도메인을 등록하는 기능으로 cors를 제한할 예정이므로
db에 도메인을 저장하기 위해 domain 모델을 정의한다.
가장 중요한 User와의 관계는 1:N이다.
static associate(db) { // domain.js
db.Domain.belongsTo(db.User)
}
static assoicitae(db) { // user.js
db.User.hasMany(db.Domain)
}
헤더 : 토큰 종류와 해시 알고리즘 정보가 들어있다.
페이로드 : 토큰의 내용물이 인코딩된 부분이다. 외부에 노출되도 좋은 자료만 넣는다
시그니처 : 토큰의 내용물을 해시함수에 서버에 보관중인 jwt_secret으로 해싱한 결괏값
jwt을 전송받은 서버는 가지고 있는 jwt_secret으로 헤더와 페이로드를 다시 해싱하고, 해싱한 결괏값과 jwt이 가지고 있는 시그니처가 동일하면 유효한 토큰, 다르면 토큰을 인증해주지 않는다.
jwt을 주고 받으면 네트워크 부하가 커지지만, db I/O가 줄어드는 효과가 있다. 선택은 개발자 몫.
npm i jsonwebtoken
middlewares.js의 verifyToken 미들웨어가 토큰 활용의 핵심이다.
verifyToken이 성공하면 req객체의 decode에 토큰 정보를 담아서 req객체를 다음 미들웨어로 던져준다.
const jwt = require('jsonwebtoken');
exports.verifyToken = (req, res, next) => {
try {
req.decoded = jwt.verify(req.headers.authorization, process.env.JWT_SECRET)
return next();
} catch (err) {
if (err.name === 'TokenExpiredError') {
return res.status(419).json({
code:419,
message:'Your Token Expired!"
});
}
return res.status(401).json({
code:401,
message:'Invalid Token'
});
}
};
routes/v1.js
const token = jwt.sign({
id: domain.User.id,
nick: domain.User.nick,
}, process.env.JWT_SECRET, {
expiresIn: '1m',
issuer: 'nodebird-api'
});
return res.json({ code: 200, message: 'Token Issued', token});
axios 사용해서 서버에서 서버로 호출구현
req.decoded 객체에 담겨있는 jwt를 활용한
아래의 패키지를 설치하고..
npm i express-rate-limit
이렇게 미들웨어를 구현해서 활용한다.
RateLimit = require('express-rate-limit');
exports.apiLimiter = RateLimit({
windowMs: 60 * 1000,
max: 10,
handler(req, res) {
res.status(this.statusCode).json({
code:this.statusCode,
message: 'only ten requests per min allowed'
})
}
});
npm i cors
힘들지만 중요한 문법이므로 포스팅하고 넘어가자.
middleware를 특정 조건에 따라 호출하고 싶을때는 wrapping하는 미들웨어 안에서 선언과 호출을 동시에 해준다.
아래의 코드에서 cors미들웨어가 호출되는 방식을 자세히 살펴보자. domain이 있을때만 해당 domain만을 대상으로 cors를 허용해준다. 보안상 훨씬 안전하다.
router.user(async (req, res, next) => {
const domain = await Domain.findOne({
where: { host: url.parse(req.get('origin')).host },
});
if (domain) {
cors({
origin: req.get('origin'),
credentials: true,
})(req, res, next);
} else {
next();
}
});