security.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. from typing import Optional
  2. from fastapi import Depends
  3. from fastapi import Request
  4. from fastapi.security import HTTPBearer
  5. from fastapi.security import OAuth2AuthorizationCodeBearer
  6. from clean_python import PermissionDenied
  7. from clean_python.oauth2 import BaseTokenVerifier
  8. from clean_python.oauth2 import NoAuthTokenVerifier
  9. from clean_python.oauth2 import OAuth2SPAClientSettings
  10. from clean_python.oauth2 import Token
  11. from clean_python.oauth2 import TokenVerifier
  12. from clean_python.oauth2 import TokenVerifierSettings
  13. __all__ = ["get_token", "RequiresScope"]
  14. verifier: Optional[BaseTokenVerifier] = None
  15. def clear_verifier() -> None:
  16. global verifier
  17. verifier = None
  18. def set_verifier(settings: Optional[TokenVerifierSettings]) -> None:
  19. global verifier
  20. if settings is None:
  21. verifier = NoAuthTokenVerifier()
  22. else:
  23. verifier = TokenVerifier(settings=settings)
  24. def get_token(request: Request) -> Token:
  25. """A fastapi 'dependable' yielding the validated token"""
  26. global verifier
  27. assert verifier is not None
  28. return verifier(request.headers.get("Authorization"))
  29. class RequiresScope:
  30. def __init__(self, scope: str):
  31. assert scope.replace(" ", "") == scope, "spaces are not allowed in a scope"
  32. self.scope = scope
  33. async def __call__(self, token: Token = Depends(get_token)) -> None:
  34. if self.scope not in token.scope:
  35. raise PermissionDenied(f"this operation requires '{self.scope}' scope")
  36. class OAuth2SPAClientSchema(OAuth2AuthorizationCodeBearer):
  37. """A fastapi 'dependable' configuring the openapi schema for the
  38. OAuth2 Authorization Code Flow with PKCE extension.
  39. This includes the JWT Bearer token configuration.
  40. """
  41. def __init__(self, client: OAuth2SPAClientSettings):
  42. super().__init__(
  43. scheme_name="OAuth2Bearer",
  44. authorizationUrl=str(client.authorization_url),
  45. tokenUrl=str(client.token_url),
  46. )
  47. async def __call__(self) -> None:
  48. pass
  49. class JWTBearerTokenSchema(HTTPBearer):
  50. """A fastapi 'dependable' configuring the openapi schema for JWT Bearer tokens.
  51. Note: for the client-side OAuth2 flow, use OAuth2SPAClientSchema instead.
  52. """
  53. def __init__(self):
  54. super().__init__(scheme_name="OAuth2Bearer", bearerFormat="JWT")
  55. async def __call__(self) -> None:
  56. pass