python 如何根据环境在FastAPI中禁用鉴权?

n6lpvg4x  于 2023-05-05  发布在  Python
关注(0)|答案(1)|浏览(356)

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

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


Authorzation.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",
    )

这个很好用。但是我想关闭基于环境的认证。例如,我希望在localhost环境中继续输入身份验证密钥。

vtwuwzda

vtwuwzda1#

您可以创建APIKeyHeader类的子类,并覆盖__call__()方法,以使用request.client.host检查请求是否来自“安全”的client,如localhost127.0.0.1,如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界面的Authorize按钮

上面提供的示例将按预期工作,也就是说,其IP地址包含在safe_clients列表中的用户将不会被要求提供API密钥以向API发出请求,无论在访问/docs处的autodocs时Swagger UI页面中是否存在Authorize按钮。但是,如果您仍然希望从safe_clients的UI中删除Authorize按钮,您可以使用自定义中间件,如here所示,以便从OpenAPI模式(在/openapi.json中)中删除securitySchemes组件-Swagger UI实际上基于OpenAPI规范。这种方法的灵感来自前面提到的链接,以及herehere。请确保在上述示例中初始化应用后添加中间件(即afterapp = 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

相关问题