Browse Source

Fix Annotated forward reference dependencies and HTTPBasic header regression

pull/14711/head
AnshMNSoni 6 months ago
parent
commit
2d2015332b
  1. 17
      fastapi/dependencies/utils.py
  2. 51
      fastapi/security/http.py

17
fastapi/dependencies/utils.py

@ -279,11 +279,22 @@ def get_dependant(
type_hints = {} type_hints = {}
signature_params = endpoint_signature.parameters signature_params = endpoint_signature.parameters
unwrapped = inspect.unwrap(call)
globalns = getattr(unwrapped, "__globals__", {})
for param_name, param in signature_params.items(): for param_name, param in signature_params.items():
# Inject fully resolved Annotated types (including forward refs) annotation = param.annotation
if param_name in type_hints:
param = param.replace(annotation=type_hints[param_name]) # Resolve ForwardRef inside Annotated without destroying metadata
if get_origin(annotation) is Annotated:
args = list(get_args(annotation))
inner = args[0]
if isinstance(inner, ForwardRef):
inner = evaluate_forwardref(inner, globalns, globalns)
args[0] = inner
annotation = Annotated[inner, *args[1:]] # ✅ correct reconstruction
param = param.replace(annotation=annotation)
is_path_param = param_name in path_param_names is_path_param = param_name in path_param_names
param_details = analyze_param( param_details = analyze_param(
param_name=param_name, param_name=param_name,

51
fastapi/security/http.py

@ -142,55 +142,18 @@ class HTTPBasic(HTTPBase):
def __init__( def __init__(
self, self,
*, *,
scheme_name: Annotated[ scheme_name: Optional[str] = None,
Optional[str], description: Optional[str] = None,
Doc( auto_error: bool = True,
""" ):
Security scheme name.
It will be included in the generated OpenAPI (e.g. visible at `/docs`).
"""
),
] = None,
realm: Annotated[str, Doc("HTTP Basic authentication realm.")] = "fastapi",
description: Annotated[
Optional[str],
Doc(
"""
Security scheme description.
It will be included in the generated OpenAPI (e.g. visible at `/docs`).
"""
),
] = None,
auto_error: Annotated[
bool,
Doc(
"""
By default, if the HTTP Basic authentication is not provided (a
header), `HTTPBasic` will automatically cancel the request and send the
client an error.
If `auto_error` is set to `False`, when the HTTP Basic authentication
is not available, instead of erroring out, the dependency result will
be `None`.
This is useful when you want to have optional authentication.
It is also useful when you want to have authentication that can be
provided in one of multiple optional ways (for example, in HTTP Basic
authentication or in an HTTP Bearer token).
"""
),
] = True,
):
self.model = HTTPBaseModel(scheme="basic", description=description) self.model = HTTPBaseModel(scheme="basic", description=description)
self.scheme_name = scheme_name or self.__class__.__name__ self.scheme_name = scheme_name or self.__class__.__name__
self.realm = realm
self.auto_error = auto_error self.auto_error = auto_error
def make_authenticate_headers(self) -> dict[str, str]: def make_authenticate_headers(self) -> dict[str, str]:
return {"WWW-Authenticate": f'Basic realm="{self.realm}"'} return {"WWW-Authenticate": "Basic"}
async def __call__( # type: ignore async def __call__( # type: ignore
self, request: Request self, request: Request

Loading…
Cancel
Save