Make ID a generic instead of forcing UUIDs

This commit is contained in:
François Voron
2022-05-01 11:18:27 +02:00
parent 87ac51a7bd
commit 7093c9e38a
25 changed files with 143 additions and 123 deletions

View File

@@ -51,7 +51,7 @@ class Authenticator:
def __init__(
self,
backends: Sequence[AuthenticationBackend],
get_user_manager: UserManagerDependency[models.UP],
get_user_manager: UserManagerDependency[models.UP, models.ID],
):
self.backends = backends
self.get_user_manager = get_user_manager
@@ -148,7 +148,7 @@ class Authenticator:
async def _authenticate(
self,
*args,
user_manager: BaseUserManager[models.UP],
user_manager: BaseUserManager[models.UP, models.ID],
optional: bool = False,
active: bool = False,
verified: bool = False,
@@ -163,7 +163,7 @@ class Authenticator:
for backend in self.backends:
if backend in enabled_backends:
token = kwargs[name_to_variable_name(backend.name)]
strategy: Strategy[models.UP] = kwargs[
strategy: Strategy[models.UP, models.ID] = kwargs[
name_to_strategy_variable_name(backend.name)
]
if token is not None:

View File

@@ -33,7 +33,7 @@ class AuthenticationBackend(Generic[models.UP]):
self,
name: str,
transport: Transport,
get_strategy: DependencyCallable[Strategy[models.UP]],
get_strategy: DependencyCallable[Strategy[models.UP, models.ID]],
):
self.name = name
self.transport = transport
@@ -41,7 +41,7 @@ class AuthenticationBackend(Generic[models.UP]):
async def login(
self,
strategy: Strategy[models.UP],
strategy: Strategy[models.UP, models.ID],
user: models.UP,
response: Response,
) -> Any:
@@ -50,7 +50,7 @@ class AuthenticationBackend(Generic[models.UP]):
async def logout(
self,
strategy: Strategy[models.UP],
strategy: Strategy[models.UP, models.ID],
user: models.UP,
token: str,
response: Response,

View File

@@ -14,9 +14,9 @@ class StrategyDestroyNotSupportedError(Exception):
pass
class Strategy(Protocol, Generic[models.UP]):
class Strategy(Protocol, Generic[models.UP, models.ID]):
async def read_token(
self, token: Optional[str], user_manager: BaseUserManager[models.UP]
self, token: Optional[str], user_manager: BaseUserManager[models.UP, models.ID]
) -> Optional[models.UP]:
... # pragma: no cover

View File

@@ -1,5 +1,4 @@
import sys
import uuid
from datetime import datetime
from typing import TypeVar
@@ -8,12 +7,14 @@ if sys.version_info < (3, 8):
else:
from typing import Protocol # pragma: no cover
from fastapi_users import models
class AccessTokenProtocol(Protocol):
class AccessTokenProtocol(Protocol[models.ID]):
"""Access token protocol that ORM model should follow."""
token: str
user_id: uuid.UUID
user_id: models.ID
created_at: datetime
def __init__(self, *args, **kwargs) -> None:

View File

@@ -6,7 +6,7 @@ from fastapi_users import models
from fastapi_users.authentication.strategy.base import Strategy
from fastapi_users.authentication.strategy.db.adapter import AccessTokenDatabase
from fastapi_users.authentication.strategy.db.models import AP
from fastapi_users.manager import BaseUserManager, UserNotExists
from fastapi_users.manager import BaseUserManager, InvalidID, UserNotExists
class DatabaseStrategy(Strategy, Generic[models.UP, AP]):
@@ -17,7 +17,7 @@ class DatabaseStrategy(Strategy, Generic[models.UP, AP]):
self.lifetime_seconds = lifetime_seconds
async def read_token(
self, token: Optional[str], user_manager: BaseUserManager[models.UP]
self, token: Optional[str], user_manager: BaseUserManager[models.UP, models.ID]
) -> Optional[models.UP]:
if token is None:
return None
@@ -33,9 +33,9 @@ class DatabaseStrategy(Strategy, Generic[models.UP, AP]):
return None
try:
user_id = access_token.user_id
return await user_manager.get(user_id)
except UserNotExists:
parsed_id = user_manager.parse_id(access_token.user_id)
return await user_manager.get(parsed_id)
except (UserNotExists, InvalidID):
return None
async def write_token(self, user: models.UP) -> str:

View File

@@ -1,7 +1,6 @@
from typing import Generic, List, Optional
import jwt
from pydantic import UUID4
from fastapi_users import models
from fastapi_users.authentication.strategy.base import (
@@ -9,7 +8,7 @@ from fastapi_users.authentication.strategy.base import (
StrategyDestroyNotSupportedError,
)
from fastapi_users.jwt import SecretType, decode_jwt, generate_jwt
from fastapi_users.manager import BaseUserManager, UserNotExists
from fastapi_users.manager import BaseUserManager, InvalidID, UserNotExists
class JWTStrategy(Strategy, Generic[models.UP]):
@@ -36,7 +35,7 @@ class JWTStrategy(Strategy, Generic[models.UP]):
return self.public_key or self.secret
async def read_token(
self, token: Optional[str], user_manager: BaseUserManager[models.UP]
self, token: Optional[str], user_manager: BaseUserManager[models.UP, models.ID]
) -> Optional[models.UP]:
if token is None:
return None
@@ -52,11 +51,9 @@ class JWTStrategy(Strategy, Generic[models.UP]):
return None
try:
user_uiid = UUID4(user_id)
return await user_manager.get(user_uiid)
except ValueError:
return None
except UserNotExists:
parsed_id = user_manager.parse_id(user_id)
return await user_manager.get(parsed_id)
except (UserNotExists, InvalidID):
return None
async def write_token(self, user: models.UP) -> str:

View File

@@ -2,11 +2,10 @@ import secrets
from typing import Generic, Optional
import aioredis
from pydantic import UUID4
from fastapi_users import models
from fastapi_users.authentication.strategy.base import Strategy
from fastapi_users.manager import BaseUserManager, UserNotExists
from fastapi_users.manager import BaseUserManager, InvalidID, UserNotExists
class RedisStrategy(Strategy, Generic[models.UP]):
@@ -15,7 +14,7 @@ class RedisStrategy(Strategy, Generic[models.UP]):
self.lifetime_seconds = lifetime_seconds
async def read_token(
self, token: Optional[str], user_manager: BaseUserManager[models.UP]
self, token: Optional[str], user_manager: BaseUserManager[models.UP, models.ID]
) -> Optional[models.UP]:
if token is None:
return None
@@ -25,11 +24,9 @@ class RedisStrategy(Strategy, Generic[models.UP]):
return None
try:
user_uiid = UUID4(user_id)
return await user_manager.get(user_uiid)
except ValueError:
return None
except UserNotExists:
parsed_id = user_manager.parse_id(user_id)
return await user_manager.get(parsed_id)
except (UserNotExists, InvalidID):
return None
async def write_token(self, user: models.UP) -> str: