这是我的计划,但无法生成到 OpenAPI 文档的身份验证部分。
class HMACModel(BaseModel):
api_key: APIKey = APIKey(**{"in": APIKeyIn.header}, name='Api-Key')
signature: APIKey = APIKey(**{"in": APIKeyIn.header}, name='Signature')
class HMACAuth(APIKeyBase):
model = HMACModel()
scheme_name = 'HMACAuth'
async def __call__(self, request: Request):
api_key = request.headers.get('Api-Key')
signature = request.headers.get('Signature')
print(f's:{signature}, k:{api_key}')
do_some_check()
return api_key
@app.get('/')
async def test_api(req: ReqModel, api_key=Depends(HMACAuth())):
pass
Run Code Online (Sandbox Code Playgroud)
当OpenAPI对象初始化并带有分析输出时,似乎自定义模型将被忽略OpenAPI(**output)。(输出中有安全模式,但OpenAPI对象中有missd)。
(参考代码:https://github.com/tiangolo/fastapi/blob/d60dd1b60e0acd0afcd5688e5759f450b6e7340c/fastapi/openapi/utils.py#L372)
小智 1
目前,让 OpenAPI 和多 api-key 依赖关系良好地发挥作用似乎是一个突出的问题,如本期所示。
有几种方法可以处理它,其中最简单的方法是创建两个APIKeyHeader依赖项并在每个请求中使用它们。您实际上不需要从该类进行任何继承APIKeyBase,因为APIKeyHeaderFastAPI 提供的类应该自行完成该任务。
我还可能定义一个附加依赖项,将其他两个依赖项用作子依赖项,如下所示:
from typing import Optional
from fastapi import FastAPI, Depends, Security, HTTPException, status
from fastapi.security.api_key import APIKeyHeader
app = FastAPI()
class HMACAuth:
async def __call__(
self,
x_hmac_api_key: str = Depends(APIKeyHeader(name="x-hmac-api-key", scheme_name="HMACApiKey")),
x_hmac_signature: str = Depends(APIKeyHeader(name="x-hmac-signature", scheme_name="HMACSignature")),
) -> Optional[str]:
if x_hmac_api_key and x_hmac_signature:
# do whatever check is needed here
if x_hmac_api_key in ["valid-api-key"] and x_hmac_signature in ["valid-signature"]:
return x_hmac_api_key
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Not authenticated",
)
@app.get(
"/",
response_model=str,
name="app:test-api",
dependencies=[Security(HMACAuth())],
)
async def test_api() -> str:
return "success"
Run Code Online (Sandbox Code Playgroud)
然后,您需要重写应用程序的openapi方法,如文档的扩展 OpenAPI部分中所述。
原因是具有此依赖项的任何路由都会为每个子依赖项生成不同的 OpenAPI 安全模式。这意味着用户可以在 OpenAPI 文档中输入任一值并进行“身份验证”。
为了解决这个问题,你可以这样做:
from fastapi.openapi.utils import get_openapi
# ...previous code
def merge_hmac_securities(list_of_securities: List[Dict[str, List]]) -> List[dict]:
"""
Find HMACApiKey and HMACSignature securities and merge them
"""
original_securities = []
hmac_security = {}
for security in list_of_securities:
if "HMACApiKey" in security or "HMACSignature" in security:
hmac_security.update(security)
else:
original_securities.append(security)
return original_securities + ([hmac_security] if hmac_security else [])
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom title",
version="3.0.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
)
for path in openapi_schema.get("paths"):
for http_method in openapi_schema["paths"][path]:
list_of_securities = openapi_schema["paths"][path][http_method].get("security")
if list_of_securities:
merged_list_of_securities = merge_hmac_securities(list_of_securities)
openapi_schema["paths"][path][http_method]["security"] = merged_list_of_securities
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
Run Code Online (Sandbox Code Playgroud)
这样做应该可以解决您的两个问题。
| 归档时间: |
|
| 查看次数: |
3026 次 |
| 最近记录: |