目标
我的目标是构建一个简单的 api 来使用 fastapi 和 John the ripper 破解密码哈希。目前,我的 api 只接受一个带有要破解的哈希的 Post 请求和一些关于原始密码的可选信息(最小长度、最大长度等)。最终,它将将此哈希发送到运行容器化开膛手约翰的后端集群以破解哈希。为了包含我希望在 Post 请求中出现的所有信息,我创建了一个 BaseModel 子类,其中包含我需要的信息(请参见下面的代码)。
我在哪里
我想实现速率限制,以便每个 IP 地址和每分钟或每小时只允许一定数量的调用。经过一番研究,我决定使用slowapi提供的解决方案如下:
from fastapi import FastAPI
from enum import Enum
from pydantic import BaseModel
from typing import Optional
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from starlette.requests import Request
class HashType(str, Enum):
md5 = "md5"
sha1 = "sha1"
class HashRequest(BaseModel, Request):
hash: str
type: Optional[HashType] = None
min_length: Optional[int] = None
max_length: Optional[int] = None
special_chars: Optional[bool] = None
limiter = Limiter(key_func=get_remote_address)
app = FastAPI()
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
@app.post("/")
@limiter.limit("10/minute")
@limiter.limit("100/hour")
async def send_hash(request: HashRequest):
## TODO: communicate with backend
return {"message":"request recieved", "hash":request.hash}
slowapi 要求将请求参数显式传递给我的端点,并且它的类型为 Starlette.requests 的请求。我的解决方案是使用多重继承,使 HashRequest 继承自 BaseModel 和 Request。
当我尝试向 api 发送 Post 请求时出现错误:AttributeError: 'Request' object has no attribute 'hash'。
发送请求的命令:
curl -X 'POST' 'http://127.0.0.1:8000/' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{
"hash":"foo"
}'