10.6 재질문…!
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);
};
0
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);노드버드 api 콘솔에 select domain 맨끝에 보시면 clientSecret` = '3b7b5e45-c56f-480f-9f3b-6d59afd800b6' 프리미엄 클라이언트 키 발급한거 나오고
GET /myposts 304 378.750 ms - -노드캣 콘솔에는 이렇게 나오는데
handler 안에서 console.log(req.user)했는데도 똑같습니다 답변감사합니다!!!
0
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 해봤는데 똑같습니다
1
router.get('/posts/my', apiLimiter, verifyToken, getMyPosts);
이거 verifyToken이 더 뒤에 있어서 apiLimit에 req.user가 없네요.
1
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);
};
0
선생님 코드 감사합니다 아쉽게도 많이 배워야할것같아서 ㅠㅜ 혹시 제가 빠트린 코드가 있을까요 ? 아니면 다른부분 확인할 사항이 있을까요? 작성한 코드 올려드립니다
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;
깃헙 질문
0
79
2
강의 1-1 수업노트의 로드맵 링크가 작동하지 않습니다.
0
74
1
aws - lightsail 이용 관련
0
56
1
4강 http 서버 만들때 ESM방식으로 해도 될까요?
0
78
2
모듈 사용 시 단점이 있나요?
0
78
1
node.js 버전 및 typescript 적용 문의
0
91
2
12.7. 방장기능(강퇴) 질문드립니다.
0
78
2
12.7 socket.js코드 그대로 뱃겨서 했는데, socket.request.session.color가안나오네요
0
67
1
12.7 코드 그대로 뱃겨서 햇는데 스샷같이 오류가뜹니다.
0
73
2
12.7.1스스로 해보기 질문되나요
0
89
3
시퀄라이즈 실습하기 질문드립니다.
0
186
9
<7-5. 시퀄라이즈 사용하기>수업 질문 드립니다.
0
94
2
크롬에서 user id를 인풋에 입력하고 등록하면 404 에러처리 페이지가 뜹니다.
0
109
2
구매 결제관련 질문입니다 !
0
120
1
다수의 supertest 가 실행될 때 force:true로 인한 DB 초기화 문제
0
130
2
node 설치 방법이 전혀다르게 바뀐것 같습니다.
0
147
2
12강 깃허브에 있는 12.7 chat.html 복붙했는데 css오류
0
119
2
무료/프리미엄 동시 소유 시 질문
0
113
1
비주얼 스튜디오 코드로 계속 진행해도 괜찮을까요?
0
133
2
10강 cors에러 localhost:4000으로 접속했을때 에러
1
155
2
webstorm 해결할 수 없는 변수 문제
0
152
2
혹시 몽고DB 쓸거면 MySQL 강의 스킵해도 되나요?
0
146
2
LightSail 실행 중 오류 질문드립니다!
0
198
2
RedisStore 사용법 질문
0
129
2





