해결된 질문
작성
·
508
·
수정됨
0
exports.apiLimiter = async (req, res, next) => {
let user;
if (res.locals.decoded) {
user = await User.findOne({ where: { id: res.locals.decoded.id } });
}
rateLimit({
widowMs: 60 * 1000,
max: user?.type === "premium" ? 10 : 1,
handler(req, res) {
res.status(this.statusCode).json({
code: this.statusCode,
message: "1분에 열 번만 요청 할 수 있습니다...",
});
},
})(req, res, next);
};
Api 프리미엄고객만 1분에 열번만요청할수있게 미들웨어 확장패턴으로
만들었습니다 그런데 localhost:4000/myposts 접속해서 10 번이상새로고침해도 api가 제한이 안되고 제가작성한 게시글 목록만 뜹니다
답변 1
0
이 부분 apiLimiter가 호출될 때마다 rateLimit 미들웨어가 새로 생성되서 그렇습니다. 다음과 같이 수정해야할 것 같네요.
const limiter = rateLimit({
widowMs: 60 * 1000,
max: (req, res) => {
if (req.user?.type === 'premium') { return 10 }
return 1;
},
handler(req, res) {
res.status(this.statusCode).json({
code: this.statusCode,
message: `1분에 ${req.user?.type === 'premium' ? '열' : '한'} 번만 요청 할 수 있습니다...`,
});
},
});
exports.apiLimiter = async (req, res, next) => {
let user;
if (res.locals.decoded) {
user = await User.findOne({ where: { id: res.locals.decoded.id } });
}
req.user = user;
limiter(req, res, next);
};
Executing (default): SELECT `id`, `host`, `type`, `clientSecret`, `createdAt`, `updatedAt`, `deletedAt`, `UserId` FROM `domains` AS `Domain` WHERE (`Domain`.`deletedAt` IS NULL AND `Domain`.`host` = 'localhost:4000') LIMIT 1;
Executing (default): SELECT `Domain`.`id`, `Domain`.`host`, `Domain`.`type`, `Domain`.`clientSecret`, `Domain`.`createdAt`, `Domain`.`updatedAt`, `Domain`.`deletedAt`, `Domain`.`UserId`, `User`.`id` AS `User.id`, `User`.`email` AS `User.email`, `User`.`nick` AS `User.nick`, `User`.`password` AS `User.password`, `User`.`provider` AS `User.provider`, `User`.`snsId` AS `User.snsId`, `User`.`createdAt` AS `User.createdAt`, `User`.`updatedAt` AS `User.updatedAt`, `User`.`deletedAt` AS `User.deletedAt` FROM `domains` AS `Domain` LEFT OUTER JOIN `Users` AS `User` ON `Domain`.`UserId` = `User`.`id` AND (`User`.`deletedAt` IS NULL) WHERE (`Domain`.`deletedAt` IS NULL AND `Domain`.`clientSecret` = '3b7b5e45-c56f-480f-9f3b-6d59afd800b6') LIMIT 1;
POST /v2/token 200 165.745 ms - 253
Executing (default): SELECT `id`, `host`, `type`, `clientSecret`, `createdAt`, `updatedAt`, `deletedAt`, `UserId` FROM `domains` AS `Domain` WHERE (`Domain`.`deletedAt` IS NULL AND `Domain`.`host` = 'localhost:4000') LIMIT 1;
Executing (default): SELECT `id`, `email`, `nick`, `password`, `provider`, `snsId`, `createdAt`, `updatedAt`, `deletedAt` FROM `Users` AS `User` WHERE (`User`.`deletedAt` IS NULL AND `User`.`id` = 2);
GET /myposts 304 378.750 ms - -
노드캣 콘솔에는 이렇게 나오는데
handler 안에서 console.log(req.user)했는데도 똑같습니다 답변감사합니다!!!
const limiter = rateLimit({
widowMs: 60 * 1000,
max: async(req, res) => {
if (await req.user?.type === 'premium') { return 10 }
return 1;
},
handler(req, res) {
console.log(req.user)
console.log(req.rateLimit)
res.status(this.statusCode).json({
code: this.statusCode,
message: `1분에 ${req.user?.type === 'premium' ? '열' : '한'} 번만 요청 할 수 있습니다...`,
});
},
});
exports.apiLimiter = async (req, res, next) => {
let user;
if (res.locals.decoded) {
user = await User.findOne({ where: { id: res.locals.decoded.id } });
}
req.user = user;
limiter(req, res, next);
};
여기 공식문서에 혹시나해서 max부분에 async await 해봤는데 똑같습니다
router.get('/posts/my', apiLimiter, verifyToken, getMyPosts);
이거 verifyToken이 더 뒤에 있어서 apiLimit에 req.user가 없네요.
const limiter = rateLimit({
widowMs: 60 * 1000,
max: (req, res) => {
if (req.user?.Domains[0]?.type === 'premium') { return 10 }
return 1;
},
handler(req, res) {
res.status(this.statusCode).json({
code: this.statusCode,
message: `1분에 ${req.user?.Domains[0]?.type === 'premium' ? '열' : '한'} 번만 요청 할 수 있습니다...`,
});
},
});
exports.apiLimiter = async (req, res, next) => {
let user;
if (res.locals.decoded) {
user = await User.findOne({ where: { id: res.locals.decoded.id }, include: { model: Domain } });
}
req.user = user;
limiter(req, res, next);
};
선생님 코드 감사합니다 아쉽게도 많이 배워야할것같아서 ㅠㅜ 혹시 제가 빠트린 코드가 있을까요 ? 아니면 다른부분 확인할 사항이 있을까요? 작성한 코드 올려드립니다
nodebird-api -> middlewares-> index.js
const jwt = require("jsonwebtoken"); //토큰을 검사하는 미들웨어
const rateLimit = require("express-rate-limit");
const User = require("../models/user");
const { Domain } = require("../models/");
const cors = require("cors");
exports.isLoggedIn = (req, res, next) => {
if (req.isAuthenticated()) {
next();
} else {
res.status(403).send("로그인 필요");
}
};
exports.isNotLoggedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
// 패스포트 통해서 로그인 안했으면
next();
} else {
const message = encodeURIComponent("로그인한 상태입니다.");
res.redirect(`/?error=${message}`); //localhost:8001? error=메시지
}
};
//토근검사
exports.verifyToken = (req, res, next) => {
try {
res.locals.decoded = jwt.verify(
req.headers.authorization,
process.env.JWT_SECRET
);
return next();
} catch (error) {
if (error.name === "TokenExpiredError") {
return res.status(419).json({
code: 419,
message: "토큰이 만료되었습니다.",
});
}
return res.status(401).json({
code: 401,
message: "유효하지 않은 토큰입니다.",
});
}
};
const limiter = rateLimit({
widowMs: 60 * 1000,
max: (req, res) => {
if (req.user?.Domains[0]?.type === "premium") {
return 10;
}
return 1;
},
handler(req, res) {
res.status(this.statusCode).json({
code: this.statusCode,
message: `1분에 ${
req.user?.Domains[0]?.type === "premium" ? "열" : "한"
} 번만 요청 할 수 있습니다...`,
});
},
});
exports.apiLimiter = async (req, res, next) => {
let user;
if (res.locals.decoded) {
user = await User.findOne({
where: { id: res.locals.decoded.id },
include: { model: Domain },
});
}
req.user = user;
limiter(req, res, next);
};
exports.deprecated = (req, res) => {
res.status(410).json({
code: 410,
message: "새로운 버전이 나왔습니다. 새로운 버전을 사용하세요",
});
};
exports.corsWhenDomainMatches = async (req, res, next) => {
const domain = await Domain.findOne({
where: { host: new URL(req.get("origin")).host },
});
if (domain) {
cors({
origin: true,
Credential: true,
})(req, res, next); //미들웨어 확장패턴
} else {
next();
}
};
nodebird-api -> routes -> v2.js
const express = require("express");
const {
verifyToken,
apiLimiter,
corsWhenDomainMatches,
} = require("../middlewares");
const {
createToken,
tokenTest,
getMyPosts,
getPostsByHashtag,
} = require("../controllers/v2");
const cors = require("cors");
const router = express.Router();
router.use(corsWhenDomainMatches);
router.use(
cors({
origin: true,
credentials: true, //쿠키요청
})
);
router.post("/token", apiLimiter, createToken);
router.get("/test", verifyToken, apiLimiter, tokenTest);
router.get("/posts/my", verifyToken, apiLimiter, getMyPosts);
// GET /v2/posts/hashtag/:title
router.get("/posts/hashtag/:title", verifyToken, apiLimiter, getPostsByHashtag);
module.exports = router;
선생님 감사합니다^^