基于Node.js级别(API密钥)的速率限制

时间:2020-05-13 09:56:13

标签: mysql node.js express

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

例如,我想限制路径loss = tf.math.reduce_mean( tf.nn.softmax_cross_entropy_with_logits(one_hot_labels, logits)) 。但是大多数速率限制对每个人都具有1个速率限制。我想使用可由用户生成的api密钥。人们每天可以生成免费的api,比如说1000个请求。然后,如果他们支付一些钱,则每天可以收到5000个请求。

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

有人对此有任何解决方案吗?

1 个答案:

答案 0 :(得分:1)

构建项目的一种方法是:

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

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

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

如果找到了API密钥,并且密钥密钥已达到1k,则表明用户已达到限制。

这是一个基本实现,效率不是很高,您需要将API密钥缓存在内存中,或者仅在nodejs中的哈希图中,或者使用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密钥