如何使用 FastAPI 通过 Swagger UI 发送授权标头?

ben*_*min 5 python swagger reactjs swagger-ui fastapi

在前端,我有以下 JS 函数:

export const uploadFormData = async (
    token: string,
    email: string,
    formInfo: Array<Object>,
): Promise<any> => {
    const formData = new FormData();
    formData.append('email', email);
    formData.append('form_info', JSON.stringify({ formInfo }));
    return fetch(
        `${process.env.ENDPOINT}/upload_form_data/`,
        {
            method: 'POST',
            headers: {
                Authorization: `Token ${token}`,
            },
            body: formData,
        },
    ).then((response) => {
        console.log(response.body?.getReader());
        if (response.status === 404) {
            throw Error('Url not found');
        }
        if (response.status === 422) {
            throw Error('Wrong request format');
        }
        if (response.status !== 200) {
            throw Error('Something went wrong with uploading the form data.');
        }
        const data = response.json();
        return {
            succes: true,
            data,
        };
    }).catch((error) => Promise.reject(error));
};
Run Code Online (Sandbox Code Playgroud)

它将POST请求发送到 FastAPI 后端中的以下端点:

@app.post("/api/queue/upload_form_data/")
async def upload_form_data(
    email: str = Body(...),  
    form_info: str = Body(...), 
    authorization: str = Header(...),
    
):
    return 'form data processing'
Run Code Online (Sandbox Code Playgroud)

但是,它不断抛出以下错误:

  1. 在前端:

    POST http://localhost:8000/api/queue/upload_form_data/ 422 (Unprocessable Entity)
    Uncaught (in promise) Error: Wrong request format
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在后台:

    POST /api/queue/upload_form_data/ HTTP/1.1" 400 Bad Request
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在 Swagger UI(响应正文)中:

    {
      "detail": [
        {
          "loc": [
            "header",
            "authorization"
          ],
          "msg": "field required",
          "type": "value_error.missing"
        }
      ]
    }
    
    Run Code Online (Sandbox Code Playgroud)

导致这些错误的请求有什么问题?

Chr*_*ris 9

在 Swagger/OpenAPI 规范中,Authorization是一个保留标头\xe2\x80\x94 以及AcceptContent-Type头\xe2\x80\x94,用于 Swagger 的内置身份验证/授权功能(请参阅Swagger 文档)。因此,他们不被允许对它们进行定义。

\n

如果您使用 Swagger,则不能Authorization在端点中定义标头参数并期望它起作用,因为通过 Swagger UI 提交请求时它将被忽略,并且您将收到一条422 Unprocessable Entity错误消息,其中包含以下内容标题authorization是错误的(就像您问题中发布的错误一样)。

\n

解决方案

\n

解决方案1

\n

如果您不需要Swagger UI 来测试您的应用程序,您可以保持原样并继续使用 JavaScript Fetch APIAuthorization ,并在标头中传递。例如:

\n
from fastapi import Header\n\n@app.post(\'/\')\ndef main(authorization: str = Header(...)):\n    return authorization\n
Run Code Online (Sandbox Code Playgroud)\n

另请注意,您实际上不必Header在端点中定义任何参数,因为您始终可以通过Request对象直接访问它们,例如:

\n
from fastapi import Request\n\n@app.post(\'/\')\ndef main(request: Request):\n    authorization = request.headers.get(\'Authorzation\')\n    return authorization\n
Run Code Online (Sandbox Code Playgroud)\n

解决方案2

\n

如果您确实需要它与 Swagger UI 一起使用,一种解决方案是使用 FastAPI HTTPBearer,它允许您在 Swagger UI 自动文档中单击Authorize屏幕右上角的按钮(位于/docs),您可以在字段中输入您的 API 密钥ValueAuthorization这将在请求标头中设置标头。例子:

\n
from fastapi import FastAPI, Depends\nfrom fastapi.security import HTTPBearer\n\napp = FastAPI()\nsecurity = HTTPBearer()\n\n@app.get(\'/\')\ndef main(authorization: str = Depends(security)):\n    return authorization.credentials\n
Run Code Online (Sandbox Code Playgroud)\n

或者,您可以使用APIKeyHeader所需的name标头(在您的情况下,即Authorization),这也允许您单击AuthorizeSwagger UI 中的按钮,以设置标头值。

\n
from fastapi import FastAPI, Security\nfrom fastapi.security.api_key import APIKeyHeader\n\napp = FastAPI()\napi_key_header = APIKeyHeader(name=\'Authorization\')\n\n@app.get(\'/\')\ndef main(api_key: str = Security(api_key_header)):\n    return api_key \n
Run Code Online (Sandbox Code Playgroud)\n

解决方案3

\n

另一种解决方案是将authorization Header参数重命名为其他名称,例如 ,token并按照OptionalAPI 端点中的方式定义此参数。然后,在端点内,检查 API 密钥是否在 或token参数request.headers.get(\'Authorization\')\xe2\x80\x94 中,如果两者都返回None,则意味着未提供令牌。例子:

\n
from fastapi import FastAPI, Request, Header\nfrom typing import Optional\n\napp = FastAPI()\n\n@app.get(\'/\')\ndef main(request: Request, token: Optional[str] = Header(None)):\n    authorization = request.headers.get(\'Authorization\')\n    return token if token else authorization  \n
Run Code Online (Sandbox Code Playgroud)\n