feat(): yandex and email sign in

This commit is contained in:
doas root
2025-11-19 01:27:15 +03:00
parent 81cf298b5a
commit 8c7ce13922
5 changed files with 191 additions and 13 deletions
@@ -22,3 +22,13 @@ class AuthError(ApplicationError):
@to_error
class InvalidCodeError(ApplicationError):
pass
@to_error
class InvalidCredentialsError(ApplicationError):
pass
@to_error
class UserNotFoundError(ApplicationError):
pass
@@ -0,0 +1,99 @@
from template_project.application.access_token.cryptographer import AccessTokenCryptographer
from template_project.application.access_token.entity_factory import AccessTokenFactory
from template_project.application.auth_identity.data_gateway import AuthIdentityDataGateway
from template_project.application.auth_identity.entity import AuthMethod
from template_project.application.auth_identity.errors import (
AuthError,
InvalidCodeError,
InvalidCredentialsError,
UserNotFoundError,
)
from template_project.application.common.containers import SecretString
from template_project.application.common.data_structure import to_data_structure
from template_project.application.common.interactor import to_interactor
from template_project.application.common.oauth.yandex import (
OAuthClient as YandexOAuthClient,
OAuthExchangeCodeError,
OAuthLoadUserInfoError,
)
from template_project.application.common.unit_of_work import UnitOfWork
from template_project.application.user.entity import UserId
from template_project.application.user.password_utils import PasswordVerifying
@to_data_structure
class UserSignInResponse:
user_id: UserId
access_token: str
@to_interactor
class SignInInteractor:
unit_of_work: UnitOfWork
password_verifying: PasswordVerifying
auth_identity_data_gateway: AuthIdentityDataGateway
access_token_factory: AccessTokenFactory
access_token_cryptographer: AccessTokenCryptographer
yandex_oauth_client: YandexOAuthClient
async def sign_in_email(
self,
email: str,
password: SecretString,
) -> UserSignInResponse:
auth_identity = await self.auth_identity_data_gateway.load_by_method_and_identifier(
method=AuthMethod.EMAIL,
identifier=email,
)
if not auth_identity:
raise UserNotFoundError
if not auth_identity.secret_key:
raise InvalidCredentialsError
is_password_valid = self.password_verifying.verify(
verifiable_password=password,
hashed_password=auth_identity.secret_key,
)
if not is_password_valid:
raise InvalidCredentialsError
access_token = self.access_token_factory.execute(auth_identity.user_id)
crypted_access_token = self.access_token_cryptographer.crypto(access_token.id)
await self.unit_of_work.add(access_token)
await self.unit_of_work.commit()
return UserSignInResponse(user_id=auth_identity.user_id, access_token=crypted_access_token)
async def sign_in_yandex(self, code: str) -> UserSignInResponse:
try:
token_response = await self.yandex_oauth_client.exchange_code(code)
access_token_yandex = token_response.access_token
except OAuthExchangeCodeError as error:
raise InvalidCodeError from error
try:
user_info = await self.yandex_oauth_client.load_user_info(access_token_yandex)
except OAuthLoadUserInfoError as error:
raise AuthError from error
auth_identity = await self.auth_identity_data_gateway.load_by_method_and_identifier(
method=AuthMethod.YANDEX,
identifier=user_info.user_id,
)
if not auth_identity:
raise UserNotFoundError
access_token = self.access_token_factory.execute(auth_identity.user_id)
crypted_access_token = self.access_token_cryptographer.crypto(access_token.id)
await self.unit_of_work.add(access_token)
await self.unit_of_work.commit()
return UserSignInResponse(user_id=auth_identity.user_id, access_token=crypted_access_token)
@@ -23,7 +23,7 @@ class UserSignUpResponse:
@to_interactor
class AuthIdentityInteractor:
class SignUpInteractor:
unit_of_work: UnitOfWork
password_hasher: PasswordHasher
auth_identity_data_gateway: AuthIdentityDataGateway