【问题标题】:Node.js level(api key) based rate limit基于 Node.js 级别(api key)的速率限制
【发布时间】:2020-05-13 20:43:51
【问题描述】:

我花了最后一个小时试图寻找一种解决方案来限制我的 api。

例如,我想限制路径/users。但大多数速率限制适用于每个人的 1 个速率限制。我想使用可由用户生成的 api 密钥。人们可以生成免费的 api,比如说每天 1000 个请求。然后,如果他们支付一些钱,他们每天可以收到 5000 个请求。

我想将这些 api 密钥存储在 mysql 数据库中。

有没有人可以解决这个问题?

【问题讨论】:

    标签: mysql node.js express


    【解决方案1】:

    构建项目的一种方法是:

    user_keys 表,包括 api 密钥、用户、创建时间和到目前为止的使用次数。 当用户尝试生成密钥时,请检查该密钥是否不存在,然后将其添加到数据库中。

    当请求到达时,检查key是否存在,如果存在,执行以下操作:

    1:如果自创建日期起已经 24 小时,则将使用次数设置为 0 2:增加使用次数

    如果您找到 API 密钥并且它是 1k,则用户达到了他的限制。

    这是一个基本的实现,效率不高,您需要将 API 密钥缓存在内存中,或者只是在 nodejs 中的 hashmap 中,或者使用 memcached/redis。但是,在尝试优化它之前先让它工作。

    编辑:一些代码示例

    //overly simple in memory cache
    const apiKeys = {}
    
    //one day's worth in milliseconds, used later on
    const oneDayTime = 1000 * 60 * 60 * 24
    
    //function to generate new API keys
    function generateKey(user) {
      if (apiKeys[user]) {
        throw Error("user already has a key")
      }
      let key = makeRandomHash(); // just some function that creates a random string like "H#4/&DA23#$X/"
    
      //share object so it can be reached by either key or user
      //terrible idea, but when you save this in mysql you can just do a normal search query
      apiKeys[user] = {
        key: key,
        user: user,
        checked: Date.Now(),
        uses: 0
      }
      apiKeys[key] = apiKeys[user]
    }
    
    // a function that does all the key verification for us
    function isValid(key) {
      //check if key even exists first
      if (!apiKeys[key]) throw Error("invalid key")
    
      //if it's been a whole day since it was last checked, reset its uses
      if (Date.now() - apiKeys[key].checked >= oneDayTime) {
        apiKeys[key].uses = 0
        apiKeys[key].checked = Date.now()
      }
    
      //check if the user limit cap is reached
      if (apiKeys[key].uses >= 1000) throw error("User daily qouta reached");
    
      //increment the user's count and exit the function without errors
      apiKeys[key].uses++;
    }
    
    //express middleware function
    function limiter(req, res, next) {
      try {
        // get the API key, can be anywhere, part of json or in the header or even get query
        let key = req.body["api_key"]
        // if key is not valid, it will error out
        isValid(key)
        // pass on to the next function if there were no errors
        next()
      } catch (e) {
        req.send(e)
      }
    }

    这是一个简单想法的过度简化的实现,但我希望它能传达这个想法。

    您要在此处更改的主要内容是 API 密钥的保存和检索方式

    【讨论】:

    • 感谢您帮助解决我的问题
    • 代码会有所帮助,但也许有人可能会给出更好的代码。但是我会用什么来生成我在想 jwt 的 api 密钥,但我认为每次请求都传递 api 密钥会更好
    猜你喜欢
    • 1970-01-01
    • 2017-02-03
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    相关资源
    最近更新 更多