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.
|
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.
|
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.
|
7
|
-
spakky_fastapi-0.7.
|
8
|
-
spakky_fastapi-0.7.
|
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,,
|
File without changes
|