spakky-fastapi 0.7.4__py3-none-any.whl → 0.7.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,82 @@
1
+ from typing import Any, TypeVar, Protocol, Awaitable, runtime_checkable
2
+ from inspect import signature
3
+ from logging import Logger
4
+ from dataclasses import InitVar, field, dataclass
5
+
6
+ from fastapi import Body, Depends, Response, status
7
+ from fastapi.security import OAuth2PasswordBearer
8
+ from spakky.aop.advice import Around
9
+ from spakky.aop.advisor import IAsyncAdvisor
10
+ from spakky.aop.aspect import AsyncAspect
11
+ from spakky.bean.autowired import autowired
12
+ from spakky.core.annotation import FunctionAnnotation
13
+ from spakky.core.types import AsyncFunc, P
14
+ from spakky.cryptography.error import InvalidJWTFormatError, JWTDecodingError
15
+ from spakky.cryptography.jwt import JWT
16
+ from spakky.cryptography.key import Key
17
+
18
+ R_co = TypeVar("R_co", covariant=True)
19
+
20
+
21
+ @runtime_checkable
22
+ class IAuthenticatedFunction(Protocol[P, R_co]):
23
+ __defaults__: tuple[Any, ...] | None
24
+ __kwdefaults__: dict[str, Any] | None
25
+
26
+ # pylint: disable=no-self-argument
27
+ def __call__(
28
+ self_, # type: ignore
29
+ self: Any,
30
+ token: JWT,
31
+ *args: P.args,
32
+ **kwargs: P.kwargs,
33
+ ) -> Awaitable[R_co]:
34
+ raise NotImplementedError
35
+
36
+
37
+ @dataclass
38
+ class JWTAuth(FunctionAnnotation):
39
+ token_url: InitVar[str]
40
+ authenticator: OAuth2PasswordBearer = field(init=False)
41
+
42
+ def __post_init__(self, token_url: str) -> None:
43
+ self.authenticator = OAuth2PasswordBearer(tokenUrl=token_url)
44
+
45
+ def __call__(
46
+ self, obj: IAuthenticatedFunction[P, R_co]
47
+ ) -> IAuthenticatedFunction[P, R_co]:
48
+ parameters = list(signature(obj).parameters.values())
49
+ if obj.__defaults__ is not None:
50
+ extra = obj.__defaults__
51
+ else:
52
+ extra = tuple(Body() for x in parameters[1:] if x.name != "token")
53
+ obj.__defaults__ = (Depends(self.authenticator),) + extra
54
+ return super().__call__(obj)
55
+
56
+
57
+ @AsyncAspect()
58
+ class AsyncJWTAuthAdvisor(IAsyncAdvisor):
59
+ __logger: Logger
60
+ __key: Key
61
+
62
+ @autowired
63
+ def __init__(self, logger: Logger, key: Key) -> None:
64
+ super().__init__()
65
+ self.__logger = logger
66
+ self.__key = key
67
+
68
+ @Around(JWTAuth.contains)
69
+ async def around_async(self, joinpoint: AsyncFunc, *args: Any, **kwargs: Any) -> Any:
70
+ token: str = kwargs["token"]
71
+ try:
72
+ jwt: JWT = JWT(token=token)
73
+ except (InvalidJWTFormatError, JWTDecodingError):
74
+ return Response(content=None, status_code=status.HTTP_401_UNAUTHORIZED)
75
+ else:
76
+ if jwt.is_expired:
77
+ return Response(content=None, status_code=status.HTTP_401_UNAUTHORIZED)
78
+ if jwt.verify(self.__key) is False:
79
+ return Response(content=None, status_code=status.HTTP_401_UNAUTHORIZED)
80
+ self.__logger.info(f"[{type(self).__name__}] {jwt.payload!r}")
81
+ kwargs["token"] = jwt
82
+ return await joinpoint(*args, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spakky-fastapi
3
- Version: 0.7.4
3
+ Version: 0.7.7
4
4
  Summary: Highly abstracted Framework core to use DDD & DI/IoC & AOP & Etc...
5
5
  Author: Spakky
6
6
  Author-email: sejong418@icloud.com
@@ -10,7 +10,7 @@ Classifier: Programming Language :: Python :: 3.10
10
10
  Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Requires-Dist: fastapi (>=0.109.2,<0.110.0)
13
- Requires-Dist: spakky-core (>=0.7.4)
13
+ Requires-Dist: spakky-core (>=0.7.7)
14
14
  Requires-Dist: websockets (>=12.0,<13.0)
15
15
  Description-Content-Type: text/markdown
16
16
 
@@ -1,8 +1,9 @@
1
1
  spakky_fastapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  spakky_fastapi/error.py,sha256=fAJuCZPxARY0SBhG9b-xsa2nvfXD7P49jZG1BzhRs3I,99
3
+ spakky_fastapi/jwt_auth.py,sha256=9P_qG6yoCVQb3xYHxtY9Wdh77faJSSjUoJ6P-K5j0A0,2880
3
4
  spakky_fastapi/post_processor.py,sha256=xTKJgsX4pEMDFZRl_uVac7HTYrc2q2ylXDM3iQYVRtA,2833
4
5
  spakky_fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
6
  spakky_fastapi/routing.py,sha256=3OhnnDIzaDeNhuIMWpPG17--98ti6LsgdfENsWr332g,19181
6
- spakky_fastapi-0.7.4.dist-info/METADATA,sha256=JScz0phDaFgydYZodog29NpEQQXhGRmoUcHom7paDzM,1660
7
- spakky_fastapi-0.7.4.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
8
- spakky_fastapi-0.7.4.dist-info/RECORD,,
7
+ spakky_fastapi-0.7.7.dist-info/METADATA,sha256=ts-8994w9eMn0EAv5SHXOVQ--ldDVDTIzNfOnOxQBak,1660
8
+ spakky_fastapi-0.7.7.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
9
+ spakky_fastapi-0.7.7.dist-info/RECORD,,