You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义OAuth2PasswordRequestForm异常:替换用户名为邮箱引发422错误

问题根源

你遇到的问题是FastAPI默认Swagger UI的OAuth2密码授权表单仅提供username输入框,但你的自定义表单要求必填email字段,导致通过Authorize弹窗发起的请求缺少email参数,触发missing验证错误。


解决方案

方案1:兼容Username与Email(最简便,推荐)

修改自定义表单类,让email变为可选字段,初始化时优先用email填充username,无email时则使用传入的username。这样既兼容Swagger默认表单,又支持用邮箱登录:

from fastapi import Depends, Form
from typing import Optional
from fastapi.security import OAuth2PasswordRequestForm


class OAuth2PasswordRequestFormWithIdentifier(OAuth2PasswordRequestForm):
    def __init__(
        self,
        grant_type: str = Form(default="password"),
        username: Optional[str] = Form(default=None),
        email: Optional[str] = Form(default=None),
        password: str = Form(...),
        scope: str = Form(default=""),
        client_id: Optional[str] = Form(default=None),
        client_secret: Optional[str] = Form(default=None),
        identifier: Optional[str] = Form(default=None)
    ):
        # 优先使用email作为登录标识,无email则用username
        login_identifier = email or username
        if not login_identifier:
            raise ValueError("Either username or email must be provided")
            
        super().__init__(
            grant_type=grant_type,
            username=login_identifier,
            password=password,
            scope=scope,
            client_id=client_id,
            client_secret=client_secret
        )
        self.identifier = identifier
        self.email = email  # 保留email字段供后续业务使用

修改后:

  • 通过Swagger Authorize弹窗传username时,可正常完成验证
  • 前端传email时,会自动用邮箱作为登录标识
  • 避免了必填email导致的验证错误

方案2:自定义Swagger UI的OAuth2表单(显示Email输入框)

如果希望Swagger的Authorize弹窗直接显示email输入框,可通过修改OpenAPI文档实现:

在main.py中添加自定义OpenAPI逻辑:

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

app = FastAPI()

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="你的API名称",
        version="1.0.0",
        description="你的API描述",
        routes=app.routes,
    )
    # 修改OAuth2密码流的请求参数,替换username为email
    if (
        "components" in openapi_schema
        and "securitySchemes" in openapi_schema["components"]
    ):
        oauth2_scheme = openapi_schema["components"]["securitySchemes"].get("OAuth2PasswordBearer")
        if oauth2_scheme and "flows" in oauth2_scheme:
            password_flow = oauth2_scheme["flows"].get("password")
            if password_flow:
                # 更新/token接口的请求参数定义
                token_path = openapi_schema["paths"]["/token"]["post"]["requestBody"]["content"]["application/x-www-form-urlencoded"]["schema"]
                token_path["properties"] = {
                    "grant_type": {"type": "string", "default": "password"},
                    "email": {"type": "string"},
                    "password": {"type": "string"},
                    "scope": {"type": "string", "default": ""},
                    "client_id": {"type": "string"},
                    "client_secret": {"type": "string"},
                    "identifier": {"type": "string"}
                }
                token_path["required"] = ["email", "password"]
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi

修改后,Swagger UI的Authorize弹窗会显示email输入框,完全匹配你的自定义表单要求。

方案3:临时测试方案(快速验证)

如果只是临时测试接口,可直接通过/token接口获取token后手动填入Authorize:

  1. 在Swagger UI中找到/token的POST接口,点击Try it out
  2. 输入email、password等参数,执行请求获取access_token
  3. 点击页面右上角的Authorize按钮,选择Bearer Auth,输入获取到的access_token
  4. 后续调用/用户信息端点时会自动携带token,正常返回数据

内容的提问来源于stack exchange,提问作者Ciasto piekarz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:57:34