简体   繁体   English

FastAPI 中的不同 OpenAPI 架构取决于环境

[英]Different OpenAPI schema in FastAPI depending on environment

We have a FastApi application that is hosted behind a reverse proxy.我们有一个托管在反向代理后面的 FastApi 应用程序。

The proxy authenticates the user using Kerberos and adds a X-Remote-User HTTP header to the request.代理使用 Kerberos 对用户进行身份验证,并向请求添加 X-Remote-User HTTP 标头。

This header is required by the FastApi application. FastApi 应用程序需要此标头。 Here is an example route:这是一个示例路线:

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

The X-Remote-User header is required for the request which is expected behavior.预期行为的请求需要 X-Remote-User 标头。

When we now open the Swagger Ui , the header is documented and when clicking on "Try it out", we can provide the header value.当我们现在打开Swagger Ui 时,会记录标题,当单击“试用”时,我们可以提供标题值。 在此处输入图片说明 This behavior is great for development, but in all other cases it is undesired, because that header is provided by the reverse proxy.这种行为非常适合开发,但在所有其他情况下都是不受欢迎的,因为该标头是由反向代理提供的。 For instance, we generate clients using OpenAPI Generator and the clients then all require the X-Remote-User parameter in their requests.例如,我们使用OpenAPI Generator生成客户端,然后客户端在其请求中都需要 X-Remote-User 参数。

Hence, it would be useful to have a configuration that distinguishes between the environments.因此,具有区分环境的配置将很有用。 If we are behind a reverse proxy, then the generated OpenAPI Schema by FastApi should not include the X-Remote-Header, otherwise if we are in development, it should be included.如果我们在反向代理后面,那么 FastApi 生成的 OpenAPI Schema 不应该包含 X-Remote-Header,否则如果我们在开发中,应该包含它。

What I did so far:到目前为止我做了什么:

  • I checked the documentation about security and also some source code of these modules, but I was not able to find a solution.我查看了有关安全性的文档以及这些模块的一些源代码,但找不到解决方案。
  • In the documentation, I read the section Behind a Proxy , but nothing there points me to a potential solution.在文档中,我阅读了“代理背后”部分,但没有任何内容指向我的潜在解决方案。
  • I also read about Middleware , but again, no solution.我还阅读了Middleware ,但同样没有解决方案。
  • We could change the generated OpenApi schema.我们可以更改生成的 OpenApi 架构。 I sketched this in my answer below , but this is not a very elegant solution我在下面的回答中对此进行概述,但这不是一个非常优雅的解决方案

Does anyone have a good solution to this problem?有没有人有一个很好的解决这个问题的方法?

We can use APIKeyHeader to remove the X-Remote-User header from the API signature, but still enforcing the header to be present.我们可以使用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}

When the header is not present, we get a "403 Forbidden".当标头不存在时,我们会收到“403 Forbidden”。 If it is present, we retrieve the header value.如果存在,我们将检索标头值。

The Swagger UI now has a button "Authorize" where we can fill-in the value of the X-Remote-User for testing purposes. Swagger UI 现在有一个“授权”按钮,我们可以在其中填写 X-Remote-User 的值以进行测试。

One approach is to generate the OpenApi schema as described in the documentation Extending OpenAPI .一种方法是生成 OpenApi 架构,如文档Extending OpenAPI 中所述 After the generation, remove the X-Remote-User from the schema.生成后,从架构中删除 X-Remote-User。 In the configuration could be a flag that the application it is behind a reverse proxy to execute the code conditionally:在配置中可能是一个标志,表明应用程序在反向代理后面有条件地执行代码:

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

However this is not a very elegant solution, as we need to parse the Json string and remove the different deeply-nested occurrences of the X-Remote-User header everywhere.然而,这不是一个非常优雅的解决方案,因为我们需要解析 Json 字符串并删除 X-Remote-User 标头各处的不同深度嵌套出现。 This is prone to bugs resulting in an invalid schema.这很容易出现导致无效架构的错误。 Furthermore it could break if new Rest endpoints are added.此外,如果添加新的 Rest 端点,它可能会中断。

A new param will be soon available for Header , Query and other to exclude elements from the openAPI output: include_in_schema=False一个新的参数将很快可用于HeaderQuery和其他从 openAPI 输出中排除元素: include_in_schema=False

Example:例子:

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

Here the patch state: https://github.com/tiangolo/fastapi/pull/3144这里补丁状态: https : //github.com/tiangolo/fastapi/pull/3144

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM