inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지

10.6 재질문…!

해결된 질문

588

Hongsun1

작성한 질문수 9

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가 제한이 안되고 제가작성한 게시글 목록만 뜹니다

node.js mysql mongodb express typescript socket.io jwt

답변 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

Hongsun1

선생님 감사합니다^^

0

Hongsun1

선생님 프리미엄 클라이언트 시크릿키발급하고 실행했는데 1분에 10번이아니고 1번만 요청할수있다고 뜹니다 혹시다른부분에서 문제가 생겨서 그런걸까요? ㅠㅜ

1

제로초(조현영)

handler 안에서 console.log(req.user) 해보세요

0

Hongsun1

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)했는데도 똑같습니다 답변감사합니다!!!

1

제로초(조현영)

console.log(req.user) 는 단순히 콘솔에 찍는거고 아무것도 안 바꾸니 당연히 똑같죠.

req.user값이 안 나오나요?

0

Hongsun1

localhost:4000/myposts 접속해서 새로고침하면 nodebird-api콘솔에 Req.user 값 나옵니다

1

제로초(조현영)

console.log(req.rateLimit) 도 찍어서 요청 보낼 때마다 limit을 위한 숫자 올라가는지 확인해봐야할 것 같습니다.

0

Hongsun1

console.log(req.rateLimit) 도 찍었는데 limit숫자가 1로 그대로입니다

0

Hongsun1

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);
};

급행 속도 제한 - npm (npmjs.com)

여기 공식문서에 혹시나해서 max부분에 async await 해봤는데 똑같습니다

1

제로초(조현영)

router.get('/posts/my', apiLimiter, verifyToken, getMyPosts);

이거 verifyToken이 더 뒤에 있어서 apiLimit에 req.user가 없네요.

0

Hongsun1

감사합니다 제가 밖에있어서 이따 실행하고 말씀드릴게요 ^^

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

Hongsun1

선생님 코드 감사합니다 아쉽게도 많이 배워야할것같아서 ㅠㅜ 혹시 제가 빠트린 코드가 있을까요 ? 아니면 다른부분 확인할 사항이 있을까요? 작성한 코드 올려드립니다

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