Commit 92fe172c authored by i.vasilenko@iq-adv.ru's avatar i.vasilenko@iq-adv.ru
Browse files

password reset

parent c61ef65d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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 }
+12 −0
Original line number Diff line number Diff line
@@ -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'


@@ -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'
@@ -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
+30 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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();
    }
}
+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
+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