Loading app/config/packages/security.yaml +4 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,10 @@ security: - { path: ^/api/register/send, roles: ROLE_USER } - { path: ^/api/register/check, roles: ROLE_USER } - { path: ^/api/password/reset, roles: ROLE_USER } - { path: ^/api/password/send, roles: PUBLIC_ACCESS } - { path: ^/api/password/reset/check, roles: PUBLIC_ACCESS } - { path: ^/api/profile/recovery, roles: PUBLIC_ACCESS } - { path: ^/api/profile/recovery/check, roles: PUBLIC_ACCESS } - { path: ^/api, roles: ROLE_CONFIRMED } Loading app/config/services.yaml +12 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,12 @@ services: App\Service\Action\ActionServiceInterface $sendRegisterService: '@App\Service\Action\Classes\SendRegisterCode' App\Service\Action\ActionServiceInterface $sendPasswordCodeService: '@App\Service\Action\Classes\SendResetPasswordCode' App\Service\Action\ActionServiceInterface $resetPasswordCodeService: '@App\Service\Action\Classes\ResetPasswordCode' App\Service\Action\ActionServiceInterface $resetPasswordService: '@App\Service\Action\Classes\ResetPassword' App\Service\Action\ActionServiceInterface: '@App\Service\Action\Classes\None' Loading @@ -48,6 +54,10 @@ services: App\Service\Dto\DtoServiceInterface $recoveryCodeDto: '@App\Service\Dto\Classes\RecoveryCodeDto' App\Service\Dto\DtoServiceInterface $passwordResetDto: '@App\Service\Dto\Classes\ResetPasswordCodeDto' App\Service\Dto\DtoServiceInterface $passwordDto: '@App\Service\Dto\Classes\ChangePasswordDto' App\Service\Dto\DtoServiceInterface $recoveryDto: '@App\Service\Dto\Classes\RecoveryDto' App\Service\Dto\DtoServiceInterface: '@App\Service\Dto\Classes\NoneDto' Loading @@ -71,6 +81,8 @@ services: App\Service\Send\SendServiceInterface $recoveryCodeSendService: '@App\Service\Send\Classes\Code\RecoveryCodeSendService' App\Service\Send\SendServiceInterface $passwordCodeSendService: '@App\Service\Send\Classes\Code\PasswordCodeSendService' # События JWT авторизации acme_api.event.authentication_success_listener: class: App\Listeners\JwtListener Loading app/src/Controller/AuthController.php +30 −0 Original line number Diff line number Diff line Loading @@ -3,8 +3,11 @@ namespace App\Controller; use App\Service\Action\ActionServiceInterface; use App\Service\Dto\Classes\ChangePasswordDto; use App\Service\Dto\Classes\RecoveryDto; use App\Service\Dto\Classes\RegisterCodeDto; use App\Service\Dto\Classes\RegisterDto; use App\Service\Dto\Classes\ResetPasswordCodeDto; use App\Service\Response\Classes\Response; use Nelmio\ApiDocBundle\Annotation\Model; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; Loading Loading @@ -52,4 +55,31 @@ class AuthController extends AbstractController { return $checkRegisterService->getResponse(); } #[Route('/password/reset', name: 'password_reset', methods: ['POST'])] #[OA\RequestBody( content: new OA\JsonContent(ref: new Model(type: ChangePasswordDto::class)) )] public function resetPassword(ActionServiceInterface $resetPasswordService): JsonResponse { return $resetPasswordService->getResponse(); } #[Route('/password/send', name: 'password_send', methods: ['POST'])] #[OA\RequestBody( content: new OA\JsonContent(ref: new Model(type: RecoveryDto::class)) )] public function sendResetPassword(ActionServiceInterface $sendPasswordCodeService): JsonResponse { return $sendPasswordCodeService->getResponse(); } #[Route('/password/reset/check', name: 'password_reset_check', methods: ['POST'])] #[OA\RequestBody( content: new OA\JsonContent(ref: new Model(type: ResetPasswordCodeDto::class)) )] public function resetCheckPassword(ActionServiceInterface $resetPasswordCodeService): JsonResponse { return $resetPasswordCodeService->getResponse(); } } app/src/Service/Action/Classes/ResetPassword.php 0 → 100644 +63 −0 Original line number Diff line number Diff line <?php namespace App\Service\Action\Classes; use App\Entity\User; use App\Service\Action\BaseActionService; use App\Service\Dto\Classes\ChangePasswordDto; use App\Service\Dto\DtoServiceInterface; use App\Service\Response\ResponseServiceInterface; use Doctrine\Persistence\ManagerRegistry; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; class ResetPassword extends BaseActionService { private ?User $user; public function __construct( private ResponseServiceInterface $response, private UserPasswordHasherInterface $passwordHasher, private DtoServiceInterface $passwordDto, private ManagerRegistry $doctrine, Security $security ) { $this->user = $security->getUser(); parent::__construct($response); } public function runAction(): void { /** @var ChangePasswordDto $dto */ $dto = $this->passwordDto->getClass(); if ($this->passwordHasher->isPasswordValid($this->user, $dto->oldPassword)) { $hashedPassword = $this->passwordHasher->hashPassword( $this->user, $dto->password ?: '' ); $this->user->setPassword($hashedPassword); try { $em = $this->doctrine->getManager(); $em->persist($this->user); $em->flush(); $this->response->addMessage('Пароль изменен'); } catch (\Exception $exception) { $this->response->addError('Ошибка изменения пароля'); } } else { $this->response->addError('Текущий пароль неверен'); } } public function validate(): bool { if ($this->user === null) { $this->response->addError('Вы не авторизованы'); return false; } return $this->passwordDto->validate($this->response); } } No newline at end of file app/src/Service/Action/Classes/ResetPasswordCode.php 0 → 100644 +73 −0 Original line number Diff line number Diff line <?php namespace App\Service\Action\Classes; use App\Entity\User; use App\Service\Action\BaseActionService; use App\Service\Dto\Classes\ResetPasswordCodeDto; use App\Service\Dto\DtoServiceInterface; use App\Service\Response\ResponseServiceInterface; use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; class ResetPasswordCode extends BaseActionService { public function __construct( private ResponseServiceInterface $response, private UserPasswordHasherInterface $passwordHasher, private DtoServiceInterface $passwordResetDto, private ManagerRegistry $doctrine ) { parent::__construct($response); } public function runAction(): void { /** @var ResetPasswordCodeDto $dto */ $dto = $this->passwordResetDto->getClass(); /** @var User $userExists */ $userExists = $this->doctrine->getRepository(User::class) ->findOneByUniq($dto->email, $dto->phoneNumber); if ($userExists !== null) { $currentDate = new \DateTime(); $code = $dto->code; $registerCode = $userExists->getRegisterCode(); if ($registerCode === null) { $this->response->addError('Код подтверждения не отправлен'); } else { if ($registerCodeDate = $registerCode->getDate()) { if ($registerCode->getCode() === $code && $currentDate->getTimestamp() < $registerCodeDate->getTimestamp()) { try { $hashedPassword = $this->passwordHasher->hashPassword( $userExists, $dto->password ?: '' ); $userExists->setPassword($hashedPassword); $em = $this->doctrine->getManager(); $em->persist($userExists); $em->remove($registerCode); $em->flush(); $this->response->addMessage('Пароль изменен'); } catch (\Exception $exception) { $this->response->addError('Ошибка изменения пароля'); } } else { $this->response->addError('Код недействителен'); } } else { $this->response->addError('Код недействителен'); } } } else { $this->response->addError('Пользователь не найден'); } } public function validate(): bool { return $this->passwordResetDto->validate($this->response); } } No newline at end of file Loading
app/config/packages/security.yaml +4 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,10 @@ security: - { path: ^/api/register/send, roles: ROLE_USER } - { path: ^/api/register/check, roles: ROLE_USER } - { path: ^/api/password/reset, roles: ROLE_USER } - { path: ^/api/password/send, roles: PUBLIC_ACCESS } - { path: ^/api/password/reset/check, roles: PUBLIC_ACCESS } - { path: ^/api/profile/recovery, roles: PUBLIC_ACCESS } - { path: ^/api/profile/recovery/check, roles: PUBLIC_ACCESS } - { path: ^/api, roles: ROLE_CONFIRMED } Loading
app/config/services.yaml +12 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,12 @@ services: App\Service\Action\ActionServiceInterface $sendRegisterService: '@App\Service\Action\Classes\SendRegisterCode' App\Service\Action\ActionServiceInterface $sendPasswordCodeService: '@App\Service\Action\Classes\SendResetPasswordCode' App\Service\Action\ActionServiceInterface $resetPasswordCodeService: '@App\Service\Action\Classes\ResetPasswordCode' App\Service\Action\ActionServiceInterface $resetPasswordService: '@App\Service\Action\Classes\ResetPassword' App\Service\Action\ActionServiceInterface: '@App\Service\Action\Classes\None' Loading @@ -48,6 +54,10 @@ services: App\Service\Dto\DtoServiceInterface $recoveryCodeDto: '@App\Service\Dto\Classes\RecoveryCodeDto' App\Service\Dto\DtoServiceInterface $passwordResetDto: '@App\Service\Dto\Classes\ResetPasswordCodeDto' App\Service\Dto\DtoServiceInterface $passwordDto: '@App\Service\Dto\Classes\ChangePasswordDto' App\Service\Dto\DtoServiceInterface $recoveryDto: '@App\Service\Dto\Classes\RecoveryDto' App\Service\Dto\DtoServiceInterface: '@App\Service\Dto\Classes\NoneDto' Loading @@ -71,6 +81,8 @@ services: App\Service\Send\SendServiceInterface $recoveryCodeSendService: '@App\Service\Send\Classes\Code\RecoveryCodeSendService' App\Service\Send\SendServiceInterface $passwordCodeSendService: '@App\Service\Send\Classes\Code\PasswordCodeSendService' # События JWT авторизации acme_api.event.authentication_success_listener: class: App\Listeners\JwtListener Loading
app/src/Controller/AuthController.php +30 −0 Original line number Diff line number Diff line Loading @@ -3,8 +3,11 @@ namespace App\Controller; use App\Service\Action\ActionServiceInterface; use App\Service\Dto\Classes\ChangePasswordDto; use App\Service\Dto\Classes\RecoveryDto; use App\Service\Dto\Classes\RegisterCodeDto; use App\Service\Dto\Classes\RegisterDto; use App\Service\Dto\Classes\ResetPasswordCodeDto; use App\Service\Response\Classes\Response; use Nelmio\ApiDocBundle\Annotation\Model; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; Loading Loading @@ -52,4 +55,31 @@ class AuthController extends AbstractController { return $checkRegisterService->getResponse(); } #[Route('/password/reset', name: 'password_reset', methods: ['POST'])] #[OA\RequestBody( content: new OA\JsonContent(ref: new Model(type: ChangePasswordDto::class)) )] public function resetPassword(ActionServiceInterface $resetPasswordService): JsonResponse { return $resetPasswordService->getResponse(); } #[Route('/password/send', name: 'password_send', methods: ['POST'])] #[OA\RequestBody( content: new OA\JsonContent(ref: new Model(type: RecoveryDto::class)) )] public function sendResetPassword(ActionServiceInterface $sendPasswordCodeService): JsonResponse { return $sendPasswordCodeService->getResponse(); } #[Route('/password/reset/check', name: 'password_reset_check', methods: ['POST'])] #[OA\RequestBody( content: new OA\JsonContent(ref: new Model(type: ResetPasswordCodeDto::class)) )] public function resetCheckPassword(ActionServiceInterface $resetPasswordCodeService): JsonResponse { return $resetPasswordCodeService->getResponse(); } }
app/src/Service/Action/Classes/ResetPassword.php 0 → 100644 +63 −0 Original line number Diff line number Diff line <?php namespace App\Service\Action\Classes; use App\Entity\User; use App\Service\Action\BaseActionService; use App\Service\Dto\Classes\ChangePasswordDto; use App\Service\Dto\DtoServiceInterface; use App\Service\Response\ResponseServiceInterface; use Doctrine\Persistence\ManagerRegistry; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; class ResetPassword extends BaseActionService { private ?User $user; public function __construct( private ResponseServiceInterface $response, private UserPasswordHasherInterface $passwordHasher, private DtoServiceInterface $passwordDto, private ManagerRegistry $doctrine, Security $security ) { $this->user = $security->getUser(); parent::__construct($response); } public function runAction(): void { /** @var ChangePasswordDto $dto */ $dto = $this->passwordDto->getClass(); if ($this->passwordHasher->isPasswordValid($this->user, $dto->oldPassword)) { $hashedPassword = $this->passwordHasher->hashPassword( $this->user, $dto->password ?: '' ); $this->user->setPassword($hashedPassword); try { $em = $this->doctrine->getManager(); $em->persist($this->user); $em->flush(); $this->response->addMessage('Пароль изменен'); } catch (\Exception $exception) { $this->response->addError('Ошибка изменения пароля'); } } else { $this->response->addError('Текущий пароль неверен'); } } public function validate(): bool { if ($this->user === null) { $this->response->addError('Вы не авторизованы'); return false; } return $this->passwordDto->validate($this->response); } } No newline at end of file
app/src/Service/Action/Classes/ResetPasswordCode.php 0 → 100644 +73 −0 Original line number Diff line number Diff line <?php namespace App\Service\Action\Classes; use App\Entity\User; use App\Service\Action\BaseActionService; use App\Service\Dto\Classes\ResetPasswordCodeDto; use App\Service\Dto\DtoServiceInterface; use App\Service\Response\ResponseServiceInterface; use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; class ResetPasswordCode extends BaseActionService { public function __construct( private ResponseServiceInterface $response, private UserPasswordHasherInterface $passwordHasher, private DtoServiceInterface $passwordResetDto, private ManagerRegistry $doctrine ) { parent::__construct($response); } public function runAction(): void { /** @var ResetPasswordCodeDto $dto */ $dto = $this->passwordResetDto->getClass(); /** @var User $userExists */ $userExists = $this->doctrine->getRepository(User::class) ->findOneByUniq($dto->email, $dto->phoneNumber); if ($userExists !== null) { $currentDate = new \DateTime(); $code = $dto->code; $registerCode = $userExists->getRegisterCode(); if ($registerCode === null) { $this->response->addError('Код подтверждения не отправлен'); } else { if ($registerCodeDate = $registerCode->getDate()) { if ($registerCode->getCode() === $code && $currentDate->getTimestamp() < $registerCodeDate->getTimestamp()) { try { $hashedPassword = $this->passwordHasher->hashPassword( $userExists, $dto->password ?: '' ); $userExists->setPassword($hashedPassword); $em = $this->doctrine->getManager(); $em->persist($userExists); $em->remove($registerCode); $em->flush(); $this->response->addMessage('Пароль изменен'); } catch (\Exception $exception) { $this->response->addError('Ошибка изменения пароля'); } } else { $this->response->addError('Код недействителен'); } } else { $this->response->addError('Код недействителен'); } } } else { $this->response->addError('Пользователь не найден'); } } public function validate(): bool { return $this->passwordResetDto->validate($this->response); } } No newline at end of file