open_id_connect_url.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. from typing import Annotated
  2. from annotated_doc import Doc
  3. from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel
  4. from fastapi.security.base import SecurityBase
  5. from starlette.exceptions import HTTPException
  6. from starlette.requests import Request
  7. from starlette.status import HTTP_401_UNAUTHORIZED
  8. class OpenIdConnect(SecurityBase):
  9. """
  10. OpenID Connect authentication class. An instance of it would be used as a
  11. dependency.
  12. **Warning**: this is only a stub to connect the components with OpenAPI in FastAPI,
  13. but it doesn't implement the full OpenIdConnect scheme, for example, it doesn't use
  14. the OpenIDConnect URL. You would need to subclass it and implement it in your
  15. code.
  16. """
  17. def __init__(
  18. self,
  19. *,
  20. openIdConnectUrl: Annotated[
  21. str,
  22. Doc(
  23. """
  24. The OpenID Connect URL.
  25. """
  26. ),
  27. ],
  28. scheme_name: Annotated[
  29. str | None,
  30. Doc(
  31. """
  32. Security scheme name.
  33. It will be included in the generated OpenAPI (e.g. visible at `/docs`).
  34. """
  35. ),
  36. ] = None,
  37. description: Annotated[
  38. str | None,
  39. Doc(
  40. """
  41. Security scheme description.
  42. It will be included in the generated OpenAPI (e.g. visible at `/docs`).
  43. """
  44. ),
  45. ] = None,
  46. auto_error: Annotated[
  47. bool,
  48. Doc(
  49. """
  50. By default, if no HTTP Authorization header is provided, required for
  51. OpenID Connect authentication, it will automatically cancel the request
  52. and send the client an error.
  53. If `auto_error` is set to `False`, when the HTTP Authorization header
  54. is not available, instead of erroring out, the dependency result will
  55. be `None`.
  56. This is useful when you want to have optional authentication.
  57. It is also useful when you want to have authentication that can be
  58. provided in one of multiple optional ways (for example, with OpenID
  59. Connect or in a cookie).
  60. """
  61. ),
  62. ] = True,
  63. ):
  64. self.model = OpenIdConnectModel(
  65. openIdConnectUrl=openIdConnectUrl, description=description
  66. )
  67. self.scheme_name = scheme_name or self.__class__.__name__
  68. self.auto_error = auto_error
  69. def make_not_authenticated_error(self) -> HTTPException:
  70. return HTTPException(
  71. status_code=HTTP_401_UNAUTHORIZED,
  72. detail="Not authenticated",
  73. headers={"WWW-Authenticate": "Bearer"},
  74. )
  75. async def __call__(self, request: Request) -> str | None:
  76. authorization = request.headers.get("Authorization")
  77. if not authorization:
  78. if self.auto_error:
  79. raise self.make_not_authenticated_error()
  80. else:
  81. return None
  82. return authorization