如何根据环境在 FastAPI 中禁用身份验证?

问题描述 投票:0回答:1

我有一个 FastAPI 应用程序,我通过注入依赖函数来启用

Authentication

控制器.py

router = APIRouter(
prefix="/v2/test",
tags=["helloWorld"],
dependencies=[Depends(api_key)],
responses={404: {"description": "Not found"}},

)

授权.py

async def api_key(api_key_header: str = Security(api_key_header_auth)):
if api_key_header != API_KEY:
    raise HTTPException(
        status_code=401,
        detail="Invalid API Key",
    )

这很好用。但是,我想disable 基于环境的身份验证。例如,我想在

localhost
环境中继续输入身份验证密钥。

python api authorization fastapi
1个回答
1
投票

您可以创建

APIKeyHeader
类的子类并覆盖
__call__()
方法来执行检查请求是否来自“安全”
client
,例如
localhost
127.0.0.1
,使用
request.client.host 
,如here所述。如果是这样,您可以将
api_key
设置为应用程序的
API_KEY
值,
check_api_key()
依赖函数将返回并使用该值来验证
api_key
。如果没有特定于应用程序的
API_KEY
,而是多个 api 密钥,则可以在
__call__()
check_api_key()
函数中对客户端的请求来源执行检查,并且仅当客户端的主机名不在
safe_clients
列表。

例子

from fastapi import FastAPI, Request, Depends, HTTPException
from starlette.status import HTTP_403_FORBIDDEN
from fastapi.security.api_key import APIKeyHeader
from fastapi import Security
from typing import Optional

API_KEY = 'some-api-key'
API_KEY_NAME = 'Authorization'
safe_clients = ['127.0.0.1']


class MyAPIKeyHeader(APIKeyHeader):
    async def __call__(self, request: Request) -> Optional[str]:
        if request.client.host in safe_clients:
            api_key = API_KEY
        else:
            api_key = request.headers.get(self.model.name)
            if not api_key:
                if self.auto_error:
                    raise HTTPException(
                        status_code=HTTP_403_FORBIDDEN, detail='Not authenticated'
                    )
                else:
                    return None

        return api_key


api_key_header_auth = MyAPIKeyHeader(name=API_KEY_NAME)


async def check_api_key(request: Request, api_key: str = Security(api_key_header_auth)):
    if api_key != API_KEY:
        raise HTTPException(
            status_code=401,
            detail='Invalid API Key',
        )

 
app = FastAPI(dependencies=[Depends(check_api_key)])


@app.get('/')
def main(request: Request):
    return request.client.host

从 Swagger UI 中删除
Authorize
按钮

上面提供的示例将按预期工作,即 IP 地址包含在

safe_clients
列表中的用户将不会被要求提供 API 密钥以向 API 发出请求,无论
Authorize
/docs
 处访问自动文档时,
按钮出现在 Swagger UI 页面中。但是,如果您仍然想从
Authorize
的 UI 中删除
safe_clients
按钮,您可以使用自定义中间件,如 here 所示执行一些检查,以便从中删除
securitySchemes
组件OpenAPI 模式(在
/openapi.json
中)——Swagger UI 实际上是基于 OpenAPI 规范的。这种方法的灵感来自前面提到的链接,以及herehere。请确保在上面的示例中初始化您的应用程序后添加中间件(即after
app = FastAPI(dependencies=...)

from fastapi import Response

# ... rest of the code is the same as above

app = FastAPI(dependencies=[Depends(check_api_key)])


@app.middleware("http")
async def remove_auth_btn(request: Request, call_next):
    response = await call_next(request)
    if request.url.path == '/openapi.json' and request.client.host in safe_clients:
        response_body = [section async for section in response.body_iterator]
        resp_str = response_body[0].decode()  # convert "response_body" bytes into string
        resp_dict = json.loads(resp_str)  # convert "resp_str" into dict
        del resp_dict['components']['securitySchemes']  # remove securitySchemes
        resp_str = json.dumps(resp_dict)  # convert "resp_dict" back to str
        return Response(content=resp_str, status_code=response.status_code, media_type=response.media_type)
    
    return response
    
© www.soinside.com 2019 - 2024. All rights reserved.