在Flask中是否有可以使用API​​密钥进行身份验证的方法?

Nic*_*win 37 python api api-key flask

我有一个小API,我想添加身份验证.我希望能够为API使用者生成API密钥; 然后,消费者可以使用包含其请求请求的密钥.

有没有Flask库可以做这样的事情?或者有一种典型的方法吗?我做了一个搜索,我只是真的发现了这个,这并没有真正深入.我正在寻找一个有图书馆的图书馆.

Jef*_*and 13

对于身份验证密钥,请创建随机值并将该值存储在数据库中.random()为这样的事情提供不足的熵,所以使用os.urandom().

您发布的链接有一个非常好的示例,说明如何使用装饰器功能处理事物.在装饰器函数中,检查请求中设置的appkey值,验证它在数据库中是否有效,然后返回该函数.如果appkey无效,raise AuthenticationError("Invalid appkey")那么你就完成了.

您链接的示例有点令人困惑.我喜欢如何制作一系列功能装饰器的演示更好.

def checkAppKey(fn):
    def inner(*args, **kwargs): #appkey should be in kwargs
        try:
            AppKey.get(appkey)
        except KeyError:
            raise AuthenticationError("Invalid appkey")
            #Whatever other errors can raise up such as db inaccessible
        #We were able to access that API key, so pass onward.
        #If you know nothing else will use the appkey after this, you can unset it.
        return fn(*args, **kwargs)
    return inner
Run Code Online (Sandbox Code Playgroud)

  • 我很好奇为什么你建议我使用`random`而不是生成UUID,这似乎是API密钥的典型特征. (2认同)

Hau*_*son 8

这是一个使用hashlib的函数,它对我来说效果很好:

def generate_hash_key():
    """
    @return: A hashkey for use to authenticate agains the API.
    """
    return base64.b64encode(hashlib.sha256(str(random.getrandbits(256))).digest(),
                            random.choice(['rA', 'aZ', 'gQ', 'hH', 'hG', 'aR', 'DD'])).rstrip('==')
Run Code Online (Sandbox Code Playgroud)

在应用程序中实现此功能的可能解决方案是在每个要保护的路由上应用装饰器.

例:

def get_apiauth_object_by_key(key):
    """
    Query the datastorage for an API key.
    @param ip: ip address
    @return: apiauth sqlachemy object.
    """
    return model.APIAuth.query.filter_by(key=key).first()

def match_api_keys(key, ip):
    """
   Match API keys and discard ip
   @param key: API key from request
   @param ip: remote host IP to match the key.
   @return: boolean
   """
   if key is None or ip is None:
      return False
   api_key = get_apiauth_object_by_key(key)
   if api_key is None:
      return False
   elif api_key.ip == "0.0.0.0":   # 0.0.0.0 means all IPs.
      return True
   elif api_key.key == key and api_key.ip == ip:
      return True
   return False

def require_app_key(f):
   """
   @param f: flask function
   @return: decorator, return the wrapped function or abort json object.
   """

   @wraps(f)
   def decorated(*args, **kwargs):
      if match_api_keys(request.args.get('key'), request.remote_addr):
         return f(*args, **kwargs)
      else:
         with log_to_file:
            log.warning("Unauthorized address trying to use API: " + request.remote_addr)
         abort(401)
      return decorated
Run Code Online (Sandbox Code Playgroud)

然后您可以使用装饰器:

@require_app_key
def delete_cake(version, cake_id):
   """
   Controller for API Function that gets a cake by ID
   @param cake_id: cake id
   @return: Response and HTTP code
   """
Run Code Online (Sandbox Code Playgroud)

此示例使用SQLAlchemy将密钥存储在数据库中(您可以使用SQLite).

你可以在这里看到实现:https://github.com/haukurk/flask-restapi-recipe.


jef*_*upp 2

生成 API 密钥的“典型”方法是创建 UUID(通常通过创建用户信息的某些子集 + 一些随机信息(例如当前时间)的 md5 哈希值)。

但是,所有 API 密钥都应该是 UUID。md5 创建的十六进制哈希满足这个要求,但肯定还有其他方法。

为用户创建密钥后,将其作为用户信息的一部分存储在数据库中,并检查他们的密钥(通常存储在 cookie 中)是否与您拥有的密钥相匹配。您链接到的页面(在某种程度上)描述了其实际机制。

  • 依赖于没有人知道你的密钥是如何生成的或尝试一些相对明显的模式是不好的做法。始终认为**算法**是已知的。 (9认同)
  • *通常通过创建用户信息的某些子集 + 一些随机信息(例如当前时间)的 md5 哈希* 不,不要这样做。我所要做的就是猜测某人的帐户有多久,然后就可以开始比赛了,因为我必须测试的密钥空间现在非常非常小。 (5认同)