auth next part

This commit is contained in:
2024-04-02 22:33:15 +03:00
parent 949ea9fdcf
commit b04eba9bc4
22 changed files with 298 additions and 29 deletions

View File

View File

@@ -0,0 +1,37 @@
from datetime import timedelta
from uuid import UUID
from jose import JWTError
from jose.jwt import decode, encode
from api.application.protocols.date_time import DateTimeProvider
from api.application.protocols.jwt import JwtTokenProcessor
from api.domain.user.model import UserId
from api.infrastructure.auth.jwt_settings import JwtSettings
class JoseJwtTokenProcessor(JwtTokenProcessor):
def __init__(self, jwt_options: JwtSettings, date_time_provider: DateTimeProvider) -> None:
self.jwt_options = jwt_options
self.date_time_provider = date_time_provider
def generate_token(self, user_id: UserId) -> str:
issued_at = self.date_time_provider.get_current_time()
expiration_time = issued_at + timedelta(hours=self.jwt_options.expires_in)
claims = {
"iat": issued_at,
"exp": expiration_time,
"sub": str(user_id.value),
}
return encode(claims, self.jwt_options.secret, self.jwt_options.algorithm)
def validate_token(self, token: str) -> UserId | None:
try:
payload = decode(token, self.jwt_options.secret, [self.jwt_options.algorithm])
return UserId(UUID(payload["sub"]))
except (JWTError, ValueError, KeyError):
return None

View File

@@ -0,0 +1,8 @@
from dataclasses import dataclass, field
@dataclass(frozen=True)
class JwtSettings:
secret: str
expires_in: int = field(default=2)
algorithm: str = field(default="HS256")

View File

@@ -0,0 +1,26 @@
from datetime import datetime, timedelta, timezone
from enum import Enum
from api.application.protocols.date_time import DateTimeProvider
class Timezone(Enum):
UTC = timezone.utc
GMT = timezone(timedelta(hours=0))
CET = timezone(timedelta(hours=1))
EET = timezone(timedelta(hours=2))
MSK = timezone(timedelta(hours=3))
IST = timezone(timedelta(hours=5, minutes=30))
WIB = timezone(timedelta(hours=7))
CST = timezone(timedelta(hours=8))
JST = timezone(timedelta(hours=9))
AEST = timezone(timedelta(hours=10))
NZST = timezone(timedelta(hours=12))
class SystemDateTimeProvider(DateTimeProvider):
def __init__(self, tz: Timezone) -> None:
self.tz = tz
def get_current_time(self) -> datetime:
return datetime.now(tz=self.tz.value)

View File

@@ -3,6 +3,7 @@ from functools import lru_cache
import yaml # type: ignore
from api.infrastructure.auth.jwt_settings import JwtSettings
from api.infrastructure.persistence.db_setings import DBSettings
from api.infrastructure.settings import Settings
@@ -27,4 +28,9 @@ def app_settings() -> Settings:
pg_port=int(config_data["db"]["port"]),
pg_db=config_data["db"]["database"],
),
jwt=JwtSettings(
secret=config_data["jwt"]["secret_key"],
expires_in=int(config_data["jwt"]["expires_in"]),
algorithm=config_data["jwt"]["algorithm"],
),
)

View File

@@ -1,6 +1,12 @@
from api.application.protocols.date_time import DateTimeProvider
from api.application.protocols.password_hasher import PasswordHasher
from api.infrastructure.date_time import SystemDateTimeProvider, Timezone
from api.infrastructure.security.password_hasher import Pbkdf2PasswordHasher
def get_password_hasher() -> PasswordHasher:
return Pbkdf2PasswordHasher()
def get_date_time_provider() -> DateTimeProvider:
return SystemDateTimeProvider(Timezone.UTC)

View File

@@ -14,6 +14,4 @@ def provide_create_user(
uow: Annotated[UnitOfWork, Depends(Stub(UnitOfWork))],
password_hasher: Annotated[PasswordHasher, Depends(Stub(PasswordHasher))],
) -> CreateUser:
return CreateUser(
uow=uow, user_repository=user_repository, password_hasher=password_hasher
)
return CreateUser(uow=uow, user_repository=user_repository, password_hasher=password_hasher)

View File

@@ -2,7 +2,6 @@ from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession
from api.domain.user import User, UserRepository
from api.infrastructure.persistence.models.user import UserModel
class SqlAlchemyUserRepository(UserRepository):
@@ -10,12 +9,6 @@ class SqlAlchemyUserRepository(UserRepository):
self.session = session
async def create_user(self, user: User) -> None:
# stmt = insert(UserModel).values(
# id=user.id.value,
# name=user.name.value,
# email=user.email.value,
# hashed_password=user.hashed_password,
# )
stmt = text(
"""INSERT INTO users (id, name, email, hashed_password)
VALUES(:id, :name, :email, :hashed_password)

View File

@@ -1,8 +1,10 @@
from dataclasses import dataclass
from api.infrastructure.auth.jwt_settings import JwtSettings
from api.infrastructure.persistence.db_setings import DBSettings
@dataclass()
class Settings:
db: DBSettings
jwt: JwtSettings