auth
parent
b04eba9bc4
commit
f8f5bf80c1
|
@ -1,22 +1,23 @@
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
from sqlalchemy.ext.asyncio import (AsyncEngine, AsyncSession,
|
||||||
|
async_sessionmaker)
|
||||||
|
|
||||||
from api.application.abstractions.uow import UnitOfWork
|
from api.application.abstractions.uow import UnitOfWork
|
||||||
from api.application.protocols.date_time import DateTimeProvider
|
from api.application.protocols.date_time import DateTimeProvider
|
||||||
|
from api.application.protocols.jwt import JwtTokenProcessor
|
||||||
from api.application.protocols.password_hasher import PasswordHasher
|
from api.application.protocols.password_hasher import PasswordHasher
|
||||||
|
from api.application.usecase.auth.auth_user import LoginUser
|
||||||
from api.application.usecase.auth.create_user import CreateUser
|
from api.application.usecase.auth.create_user import CreateUser
|
||||||
from api.domain.user.repository import UserRepository
|
from api.domain.user.repository import UserRepository
|
||||||
from api.infrastructure.dependencies.adapters import (
|
from api.infrastructure.dependencies.adapters import (create_engine,
|
||||||
create_engine,
|
create_session_maker,
|
||||||
create_session_maker,
|
new_session,
|
||||||
new_session,
|
new_unit_of_work)
|
||||||
new_unit_of_work,
|
|
||||||
)
|
|
||||||
from api.infrastructure.dependencies.configs import app_settings
|
from api.infrastructure.dependencies.configs import app_settings
|
||||||
from api.infrastructure.dependencies.protocols import (
|
from api.infrastructure.dependencies.protocols import (get_date_time_provider,
|
||||||
get_date_time_provider,
|
get_jwt_token_processor,
|
||||||
get_password_hasher,
|
get_password_hasher,
|
||||||
)
|
get_user_login)
|
||||||
from api.infrastructure.dependencies.repositories import get_user_repository
|
from api.infrastructure.dependencies.repositories import get_user_repository
|
||||||
from api.infrastructure.dependencies.usecases import provide_create_user
|
from api.infrastructure.dependencies.usecases import provide_create_user
|
||||||
from api.infrastructure.settings import Settings
|
from api.infrastructure.settings import Settings
|
||||||
|
@ -34,6 +35,9 @@ def init_dependencies(app: FastAPI) -> None:
|
||||||
app.dependency_overrides[DateTimeProvider] = get_date_time_provider
|
app.dependency_overrides[DateTimeProvider] = get_date_time_provider
|
||||||
app.dependency_overrides[PasswordHasher] = get_password_hasher
|
app.dependency_overrides[PasswordHasher] = get_password_hasher
|
||||||
|
|
||||||
|
app.dependency_overrides[JwtTokenProcessor] = get_jwt_token_processor
|
||||||
|
app.dependency_overrides[LoginUser] = get_user_login
|
||||||
|
|
||||||
app.dependency_overrides[UserRepository] = get_user_repository
|
app.dependency_overrides[UserRepository] = get_user_repository
|
||||||
|
|
||||||
app.dependency_overrides[CreateUser] = provide_create_user
|
app.dependency_overrides[CreateUser] = provide_create_user
|
||||||
|
|
|
@ -15,12 +15,16 @@ class LoginUser:
|
||||||
self.hasher = password_hasher
|
self.hasher = password_hasher
|
||||||
|
|
||||||
async def __call__(self, request: LoginRequest) -> AuthenticationResponse:
|
async def __call__(self, request: LoginRequest) -> AuthenticationResponse:
|
||||||
|
print("__call__ request", request)
|
||||||
user = await self.user_repository.get_user(filter={"email": request.email})
|
user = await self.user_repository.get_user(filter={"email": request.email})
|
||||||
|
print("__call__ user from repo", user)
|
||||||
error = UserInvalidCredentialsError("Email or password is incorrect")
|
error = UserInvalidCredentialsError("Email or password is incorrect")
|
||||||
if user is None:
|
if user is None:
|
||||||
|
print("user is none in LoginUser __call__")
|
||||||
raise error
|
raise error
|
||||||
|
|
||||||
if not self.hasher.verify_password(request.password, user.hashed_password):
|
if not self.hasher.verify_password(request.password, user.hashed_password):
|
||||||
|
print("wrong pass in LoginUser __call__")
|
||||||
raise error
|
raise error
|
||||||
|
|
||||||
return AuthenticationResponse(
|
return AuthenticationResponse(
|
||||||
|
|
|
@ -1,7 +1,17 @@
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Depends
|
||||||
|
|
||||||
from api.application.protocols.date_time import DateTimeProvider
|
from api.application.protocols.date_time import DateTimeProvider
|
||||||
|
from api.application.protocols.jwt import JwtTokenProcessor
|
||||||
from api.application.protocols.password_hasher import PasswordHasher
|
from api.application.protocols.password_hasher import PasswordHasher
|
||||||
|
from api.application.usecase.auth.auth_user import LoginUser
|
||||||
|
from api.domain.user.repository import UserRepository
|
||||||
|
from api.infrastructure.auth.jwt_processor import JoseJwtTokenProcessor
|
||||||
from api.infrastructure.date_time import SystemDateTimeProvider, Timezone
|
from api.infrastructure.date_time import SystemDateTimeProvider, Timezone
|
||||||
|
from api.infrastructure.dependencies.stub import Stub
|
||||||
from api.infrastructure.security.password_hasher import Pbkdf2PasswordHasher
|
from api.infrastructure.security.password_hasher import Pbkdf2PasswordHasher
|
||||||
|
from api.infrastructure.settings import Settings
|
||||||
|
|
||||||
|
|
||||||
def get_password_hasher() -> PasswordHasher:
|
def get_password_hasher() -> PasswordHasher:
|
||||||
|
@ -10,3 +20,19 @@ def get_password_hasher() -> PasswordHasher:
|
||||||
|
|
||||||
def get_date_time_provider() -> DateTimeProvider:
|
def get_date_time_provider() -> DateTimeProvider:
|
||||||
return SystemDateTimeProvider(Timezone.UTC)
|
return SystemDateTimeProvider(Timezone.UTC)
|
||||||
|
|
||||||
|
|
||||||
|
def get_jwt_token_processor(
|
||||||
|
settings: Annotated[Settings, Depends(Stub(Settings))],
|
||||||
|
date_time_provider: Annotated[DateTimeProvider, Depends(Stub(DateTimeProvider))],
|
||||||
|
) -> JwtTokenProcessor:
|
||||||
|
return JoseJwtTokenProcessor(
|
||||||
|
jwt_options=settings.jwt, date_time_provider=date_time_provider
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_login(
|
||||||
|
user_repository: Annotated[UserRepository, Depends(Stub(UserRepository))],
|
||||||
|
password_hasher: Annotated[PasswordHasher, Depends(Stub(PasswordHasher))],
|
||||||
|
) -> LoginUser:
|
||||||
|
return LoginUser(user_repository=user_repository, password_hasher=password_hasher)
|
||||||
|
|
|
@ -2,6 +2,7 @@ from sqlalchemy import text
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from api.domain.user import User, UserRepository
|
from api.domain.user import User, UserRepository
|
||||||
|
from api.domain.user.model import UserEmail, UserFirstName, UserId
|
||||||
|
|
||||||
|
|
||||||
class SqlAlchemyUserRepository(UserRepository):
|
class SqlAlchemyUserRepository(UserRepository):
|
||||||
|
@ -25,7 +26,17 @@ class SqlAlchemyUserRepository(UserRepository):
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_user(self, filter: dict) -> User | None:
|
async def get_user(self, filter: dict) -> User | None:
|
||||||
pass
|
stmt = text("""SELECT * FROM users WHERE email = :val""")
|
||||||
|
result = await self.session.execute(stmt, {"val": filter["email"]})
|
||||||
|
if not result:
|
||||||
|
return None
|
||||||
|
result = result.mappings().one()
|
||||||
|
return User(
|
||||||
|
id=UserId(result.id),
|
||||||
|
name=UserFirstName(result.name),
|
||||||
|
email=UserEmail(result.email),
|
||||||
|
hashed_password=result.hashed_password,
|
||||||
|
)
|
||||||
|
|
||||||
async def get_users(self) -> list[User]:
|
async def get_users(self) -> list[User]:
|
||||||
return []
|
return []
|
||||||
|
|
|
@ -618,19 +618,6 @@ files = [
|
||||||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jose"
|
|
||||||
version = "1.0.0"
|
|
||||||
description = "An implementation of the JOSE draft"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "jose-1.0.0.tar.gz", hash = "sha256:8436c3617cd94e1ba97828fbb1ce27c129f66c78fb855b4bb47e122b5f345fba"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
pycrypto = ">=2.6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "magic-filter"
|
name = "magic-filter"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
|
@ -991,16 +978,6 @@ files = [
|
||||||
{file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"},
|
{file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pycrypto"
|
|
||||||
version = "2.6.1"
|
|
||||||
description = "Cryptographic modules for Python."
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "pycrypto-2.6.1.tar.gz", hash = "sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.5.3"
|
version = "2.5.3"
|
||||||
|
@ -1180,6 +1157,20 @@ cryptography = ["cryptography (>=3.4.0)"]
|
||||||
pycrypto = ["pyasn1", "pycrypto (>=2.6.0,<2.7.0)"]
|
pycrypto = ["pyasn1", "pycrypto (>=2.6.0,<2.7.0)"]
|
||||||
pycryptodome = ["pyasn1", "pycryptodome (>=3.3.1,<4.0.0)"]
|
pycryptodome = ["pyasn1", "pycryptodome (>=3.3.1,<4.0.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-multipart"
|
||||||
|
version = "0.0.9"
|
||||||
|
description = "A streaming multipart parser for Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"},
|
||||||
|
{file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyyaml"
|
name = "pyyaml"
|
||||||
version = "6.0.1"
|
version = "6.0.1"
|
||||||
|
@ -1205,6 +1196,7 @@ files = [
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||||
|
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||||
|
@ -1573,4 +1565,4 @@ multidict = ">=4.0"
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "cb90b25778130dc1445290f65ee84f37029b7db4838a16b510a9f2efaf5ae841"
|
content-hash = "586dbb5fd80f9999d39a1cb960a06bc8f15e3b103f1c273e4d954fca0b1ffc75"
|
||||||
|
|
|
@ -7,8 +7,8 @@ readme = "README.md"
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.10"
|
python = "^3.10"
|
||||||
jose = "^1.0.0"
|
|
||||||
python-jose = "^3.3.0"
|
python-jose = "^3.3.0"
|
||||||
|
python-multipart = "^0.0.9"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue