vendor/shopware/storefront/Controller/AuthController.php line 79

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Controller;
  3. use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
  4. use Shopware\Core\Checkout\Customer\Exception\BadCredentialsException;
  5. use Shopware\Core\Checkout\Customer\Exception\CustomerAuthThrottledException;
  6. use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundByHashException;
  7. use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundException;
  8. use Shopware\Core\Checkout\Customer\Exception\CustomerRecoveryHashExpiredException;
  9. use Shopware\Core\Checkout\Customer\Exception\InactiveCustomerException;
  10. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLoginRoute;
  11. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLogoutRoute;
  12. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractResetPasswordRoute;
  13. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractSendPasswordRecoveryMailRoute;
  14. use Shopware\Core\Framework\Context;
  15. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  19. use Shopware\Core\Framework\RateLimiter\Exception\RateLimitExceededException;
  20. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  21. use Shopware\Core\Framework\Routing\Annotation\Since;
  22. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  23. use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
  24. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  25. use Shopware\Storefront\Framework\Routing\Annotation\NoStore;
  26. use Shopware\Storefront\Framework\Routing\RequestTransformer;
  27. use Shopware\Storefront\Page\Account\Login\AccountGuestLoginPageLoadedHook;
  28. use Shopware\Storefront\Page\Account\Login\AccountLoginPageLoadedHook;
  29. use Shopware\Storefront\Page\Account\Login\AccountLoginPageLoader;
  30. use Symfony\Component\HttpFoundation\Request;
  31. use Symfony\Component\HttpFoundation\Response;
  32. use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
  33. use Symfony\Component\Routing\Annotation\Route;
  34. /**
  35.  * @Route(defaults={"_routeScope"={"storefront"}})
  36.  */
  37. class AuthController extends StorefrontController
  38. {
  39.     private AccountLoginPageLoader $loginPageLoader;
  40.     private EntityRepositoryInterface $customerRecoveryRepository;
  41.     private AbstractSendPasswordRecoveryMailRoute $sendPasswordRecoveryMailRoute;
  42.     private AbstractResetPasswordRoute $resetPasswordRoute;
  43.     private AbstractLoginRoute $loginRoute;
  44.     private AbstractLogoutRoute $logoutRoute;
  45.     private CartService $cartService;
  46.     public function __construct(
  47.         AccountLoginPageLoader $loginPageLoader,
  48.         EntityRepositoryInterface $customerRecoveryRepository,
  49.         AbstractSendPasswordRecoveryMailRoute $sendPasswordRecoveryMailRoute,
  50.         AbstractResetPasswordRoute $resetPasswordRoute,
  51.         AbstractLoginRoute $loginRoute,
  52.         AbstractLogoutRoute $logoutRoute,
  53.         CartService $cartService
  54.     ) {
  55.         $this->loginPageLoader $loginPageLoader;
  56.         $this->customerRecoveryRepository $customerRecoveryRepository;
  57.         $this->sendPasswordRecoveryMailRoute $sendPasswordRecoveryMailRoute;
  58.         $this->resetPasswordRoute $resetPasswordRoute;
  59.         $this->loginRoute $loginRoute;
  60.         $this->logoutRoute $logoutRoute;
  61.         $this->cartService $cartService;
  62.     }
  63.     /**
  64.      * @Since("6.0.0.0")
  65.      * @Route("/account/login", name="frontend.account.login.page", methods={"GET"})
  66.      * @NoStore
  67.      */
  68.     public function loginPage(Request $requestRequestDataBag $dataSalesChannelContext $context): Response
  69.     {
  70.         /** @var string $redirect */
  71.         $redirect $request->get('redirectTo''frontend.account.home.page');
  72.         $customer $context->getCustomer();
  73.         if ($customer !== null && $customer->getGuest() === false) {
  74.             $request->request->set('redirectTo'$redirect);
  75.             return $this->createActionResponse($request);
  76.         }
  77.         $page $this->loginPageLoader->load($request$context);
  78.         $this->hook(new AccountLoginPageLoadedHook($page$context));
  79.         return $this->renderStorefront('@Storefront/storefront/page/account/register/index.html.twig', [
  80.             'redirectTo' => $redirect,
  81.             'redirectParameters' => $request->get('redirectParameters'json_encode([])),
  82.             'page' => $page,
  83.             'loginError' => (bool) $request->get('loginError'),
  84.             'waitTime' => $request->get('waitTime'),
  85.             'errorSnippet' => $request->get('errorSnippet'),
  86.             'data' => $data,
  87.         ]);
  88.     }
  89.     /**
  90.      * @Since("6.3.4.1")
  91.      * @Route("/account/guest/login", name="frontend.account.guest.login.page", methods={"GET"})
  92.      * @NoStore
  93.      */
  94.     public function guestLoginPage(Request $requestSalesChannelContext $context): Response
  95.     {
  96.         /** @var string $redirect */
  97.         $redirect $request->get('redirectTo''frontend.account.home.page');
  98.         $customer $context->getCustomer();
  99.         if ($customer !== null) {
  100.             $request->request->set('redirectTo'$redirect);
  101.             return $this->createActionResponse($request);
  102.         }
  103.         $waitTime = (int) $request->get('waitTime');
  104.         if ($waitTime) {
  105.             $this->addFlash(self::INFO$this->trans('account.loginThrottled', ['%seconds%' => $waitTime]));
  106.         }
  107.         if ((bool) $request->get('loginError')) {
  108.             $this->addFlash(self::DANGER$this->trans('account.orderGuestLoginWrongCredentials'));
  109.         }
  110.         $page $this->loginPageLoader->load($request$context);
  111.         $this->hook(new AccountGuestLoginPageLoadedHook($page$context));
  112.         return $this->renderStorefront('@Storefront/storefront/page/account/guest-auth.html.twig', [
  113.             'redirectTo' => $redirect,
  114.             'redirectParameters' => $request->get('redirectParameters'json_encode([])),
  115.             'page' => $page,
  116.         ]);
  117.     }
  118.     /**
  119.      * @Since("6.0.0.0")
  120.      * @Route("/account/logout", name="frontend.account.logout.page", methods={"GET"})
  121.      */
  122.     public function logout(Request $requestSalesChannelContext $contextRequestDataBag $dataBag): Response
  123.     {
  124.         if ($context->getCustomer() === null) {
  125.             return $this->redirectToRoute('frontend.account.login.page');
  126.         }
  127.         try {
  128.             $this->logoutRoute->logout($context$dataBag);
  129.             $this->addFlash(self::SUCCESS$this->trans('account.logoutSucceeded'));
  130.             $parameters = [];
  131.         } catch (ConstraintViolationException $formViolations) {
  132.             $parameters = ['formViolations' => $formViolations];
  133.         }
  134.         return $this->redirectToRoute('frontend.account.login.page'$parameters);
  135.     }
  136.     /**
  137.      * @Since("6.0.0.0")
  138.      * @Route("/account/login", name="frontend.account.login", methods={"POST"}, defaults={"XmlHttpRequest"=true})
  139.      */
  140.     public function login(Request $requestRequestDataBag $dataSalesChannelContext $context): Response
  141.     {
  142.         $customer $context->getCustomer();
  143.         if ($customer !== null && $customer->getGuest() === false) {
  144.             return $this->createActionResponse($request);
  145.         }
  146.         try {
  147.             $token $this->loginRoute->login($data$context)->getToken();
  148.             if (!empty($token)) {
  149.                 $this->addCartErrors($this->cartService->getCart($token$context));
  150.                 return $this->createActionResponse($request);
  151.             }
  152.         } catch (BadCredentialsException UnauthorizedHttpException InactiveCustomerException CustomerAuthThrottledException $e) {
  153.             if ($e instanceof InactiveCustomerException) {
  154.                 $errorSnippet $e->getSnippetKey();
  155.             }
  156.             if ($e instanceof CustomerAuthThrottledException) {
  157.                 $waitTime $e->getWaitTime();
  158.             }
  159.         }
  160.         $data->set('password'null);
  161.         return $this->forwardToRoute(
  162.             'frontend.account.login.page',
  163.             [
  164.                 'loginError' => true,
  165.                 'errorSnippet' => $errorSnippet ?? null,
  166.                 'waitTime' => $waitTime ?? null,
  167.             ]
  168.         );
  169.     }
  170.     /**
  171.      * @Since("6.1.0.0")
  172.      * @Route("/account/recover", name="frontend.account.recover.page", methods={"GET"})
  173.      */
  174.     public function recoverAccountForm(Request $requestSalesChannelContext $context): Response
  175.     {
  176.         $page $this->loginPageLoader->load($request$context);
  177.         return $this->renderStorefront('@Storefront/storefront/page/account/profile/recover-password.html.twig', [
  178.             'page' => $page,
  179.         ]);
  180.     }
  181.     /**
  182.      * @Since("6.1.0.0")
  183.      * @Route("/account/recover", name="frontend.account.recover.request", methods={"POST"})
  184.      */
  185.     public function generateAccountRecovery(Request $requestRequestDataBag $dataSalesChannelContext $context): Response
  186.     {
  187.         try {
  188.             $data->get('email')
  189.                 ->set('storefrontUrl'$request->attributes->get(RequestTransformer::STOREFRONT_URL));
  190.             $this->sendPasswordRecoveryMailRoute->sendRecoveryMail(
  191.                 $data->get('email')->toRequestDataBag(),
  192.                 $context,
  193.                 false
  194.             );
  195.             $this->addFlash(self::SUCCESS$this->trans('account.recoveryMailSend'));
  196.         } catch (CustomerNotFoundException $e) {
  197.             $this->addFlash(self::SUCCESS$this->trans('account.recoveryMailSend'));
  198.         } catch (InconsistentCriteriaIdsException $e) {
  199.             $this->addFlash(self::DANGER$this->trans('error.message-default'));
  200.         } catch (RateLimitExceededException $e) {
  201.             $this->addFlash(self::INFO$this->trans('error.rateLimitExceeded', ['%seconds%' => $e->getWaitTime()]));
  202.         }
  203.         return $this->redirectToRoute('frontend.account.recover.page');
  204.     }
  205.     /**
  206.      * @Since("6.1.0.0")
  207.      * @Route("/account/recover/password", name="frontend.account.recover.password.page", methods={"GET"})
  208.      */
  209.     public function resetPasswordForm(Request $requestSalesChannelContext $context): Response
  210.     {
  211.         $page $this->loginPageLoader->load($request$context);
  212.         $hash $request->get('hash');
  213.         if (!$hash) {
  214.             $this->addFlash(self::DANGER$this->trans('account.passwordHashNotFound'));
  215.             return $this->redirectToRoute('frontend.account.recover.request');
  216.         }
  217.         $customerHashCriteria = new Criteria();
  218.         $customerHashCriteria->addFilter(new EqualsFilter('hash'$hash));
  219.         $customerRecovery $this->customerRecoveryRepository
  220.             ->search($customerHashCriteria$context->getContext())
  221.             ->first();
  222.         if ($customerRecovery === null) {
  223.             $this->addFlash(self::DANGER$this->trans('account.passwordHashNotFound'));
  224.             return $this->redirectToRoute('frontend.account.recover.request');
  225.         }
  226.         if (!$this->checkHash($hash$context->getContext())) {
  227.             $this->addFlash(self::DANGER$this->trans('account.passwordHashExpired'));
  228.             return $this->redirectToRoute('frontend.account.recover.request');
  229.         }
  230.         return $this->renderStorefront('@Storefront/storefront/page/account/profile/reset-password.html.twig', [
  231.             'page' => $page,
  232.             'hash' => $hash,
  233.             'formViolations' => $request->get('formViolations'),
  234.         ]);
  235.     }
  236.     /**
  237.      * @Since("6.1.0.0")
  238.      * @Route("/account/recover/password", name="frontend.account.recover.password.reset", methods={"POST"})
  239.      */
  240.     public function resetPassword(RequestDataBag $dataSalesChannelContext $context): Response
  241.     {
  242.         $hash $data->get('password')->get('hash');
  243.         try {
  244.             $pw $data->get('password');
  245.             $this->resetPasswordRoute->resetPassword($pw->toRequestDataBag(), $context);
  246.             $this->addFlash(self::SUCCESS$this->trans('account.passwordChangeSuccess'));
  247.         } catch (ConstraintViolationException $formViolations) {
  248.             $this->addFlash(self::DANGER$this->trans('account.passwordChangeNoSuccess'));
  249.             return $this->forwardToRoute(
  250.                 'frontend.account.recover.password.page',
  251.                 ['hash' => $hash'formViolations' => $formViolations'passwordFormViolation' => true]
  252.             );
  253.         } catch (CustomerNotFoundByHashException $e) {
  254.             $this->addFlash(self::DANGER$this->trans('account.passwordChangeNoSuccess'));
  255.             return $this->forwardToRoute('frontend.account.recover.request');
  256.         } catch (CustomerRecoveryHashExpiredException $e) {
  257.             $this->addFlash(self::DANGER$this->trans('account.passwordHashExpired'));
  258.             return $this->forwardToRoute('frontend.account.recover.request');
  259.         }
  260.         return $this->redirectToRoute('frontend.account.profile.page');
  261.     }
  262.     private function checkHash(string $hashContext $context): bool
  263.     {
  264.         $criteria = new Criteria();
  265.         $criteria->addFilter(new EqualsFilter('hash'$hash));
  266.         $recovery $this->customerRecoveryRepository->search($criteria$context)->first();
  267.         $validDateTime = (new \DateTime())->sub(new \DateInterval('PT2H'));
  268.         return $recovery && $validDateTime $recovery->getCreatedAt();
  269.     }
  270. }