【问题标题】:Different OpenAPI schema in FastAPI depending on environmentFastAPI 中不同的 OpenAPI 模式取决于环境
【发布时间】:2020-09-17 06:43:06
【问题描述】:

我们有一个托管在反向代理后面的 FastApi 应用程序。

代理使用 Kerberos 对用户进行身份验证,并向请求添加 X-Remote-User HTTP 标头。

FastApi 应用程序需要此标头。这是一个示例路线:

@app.get("/user/me")
async def get_user_me(x_remote_user: str = Header(...)):
    return {"User": x_remote_user}

请求需要 X-Remote-User 标头,这是预期行为。

当我们现在打开Swagger Ui 时,标头已记录在案,当单击“试用”时,我们可以提供标头值。 这种行为非常适合开发,但在所有其他情况下都是不受欢迎的,因为该标头是由反向代理提供的。例如,我们使用OpenAPI Generator 生成客户端,然后客户端在其请求中都需要 X-Remote-User 参数。

因此,具有区分环境的配置会很有用。如果我们在反向代理后面,那么 FastApi 生成的 OpenAPI Schema 不应该包含 X-Remote-Header,否则如果我们正在开发中,应该包含它。

到目前为止我做了什么:

  • 我查看了有关 security 以及这些模块中的一些 source code 的文档,但找不到解决方案。
  • 在文档中,我阅读了 Behind a Proxy 部分,但其中没有任何内容指向我潜在的解决方案。
  • 我还阅读了有关 Middleware 的信息,但同样没有解决方案。
  • 我们可以更改生成的 OpenApi 架构。我在my answer below 中画了这个草图,但这不是一个非常优雅的解决方案

有没有人能很好的解决这个问题?

【问题讨论】:

    标签: openapi fastapi


    【解决方案1】:

    我们可以使用APIKeyHeader 从 API 签名中删除 X-Remote-User 标头,但仍强制标头存在。

    from fastapi.security import APIKeyHeader
    
    apiKey = APIKeyHeader(name="X-Remote-User")
    
    @app.get("/user/me")
    async def get_user_me(x_remote_user: str = Depends(apiKey)):
        return {"User": x_remote_user}
    

    当标头不存在时,我们会得到“403 Forbidden”。如果存在,我们检索标头值。

    Swagger UI 现在有一个“授权”按钮,我们可以在其中填写 X-Remote-User 的值以进行测试。

    【讨论】:

      【解决方案2】:

      一种方法是生成 OpenApi 架构,如文档 Extending OpenAPI 中所述。生成后,从架构中删除 X-Remote-User。在配置中可能是一个标志,表明应用程序在反向代理后面有条件地执行代码:

      from fastapi import FastAPI
      from fastapi.openapi.utils import get_openapi
      from MyConfig import Config
      
      
      app = FastAPI()
      
      
      @app.get("/items/")
      async def read_items():
          return [{"name": "Foo"}]
      
      if Config.reverse_proxy:
          def custom_openapi():
              if app.openapi_schema:
                  return app.openapi_schema
              openapi_schema = get_openapi(
                  title="Custom title",
                  version="2.5.0",
                  description="This is a very custom OpenAPI schema",
                  routes=app.routes,
              )
              // remove X-Remote-User here
              app.openapi_schema = openapi_schema
              return app.openapi_schema
      
      
          app.openapi = custom_openapi
      

      然而,这不是一个非常优雅的解决方案,因为我们需要解析 Json 字符串并在各处移除不同深度嵌套的 X-Remote-User 标头。这很容易出现导致无效架构的错误。此外,如果添加新的 Rest 端点,它可能会中断。

      【讨论】:

        【解决方案3】:

        HeaderQuery 和其他用于从 openAPI 输出中排除元素的新参数即将推出:include_in_schema=False

        例子:

        def test(x_forwarded_for: str = Header(None, include_in_schema=False)):
            ...
        

        这里的补丁状态:https://github.com/tiangolo/fastapi/pull/3144

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-08-19
          • 2013-01-21
          • 2012-04-12
          • 2018-04-04
          相关资源
          最近更新 更多