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

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Controller;
  3. use Shopware\Core\Checkout\Customer\Exception\BadCredentialsException;
  4. use Shopware\Core\Checkout\Customer\Exception\CustomerAuthThrottledException;
  5. use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundByHashException;
  6. use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundException;
  7. use Shopware\Core\Checkout\Customer\Exception\CustomerRecoveryHashExpiredException;
  8. use Shopware\Core\Checkout\Customer\Exception\InactiveCustomerException;
  9. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLoginRoute;
  10. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLogoutRoute;
  11. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractResetPasswordRoute;
  12. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractSendPasswordRecoveryMailRoute;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
  14. use Shopware\Core\Framework\Feature;
  15. use Shopware\Core\Framework\Log\Package;
  16. use Shopware\Core\Framework\RateLimiter\Exception\RateLimitExceededException;
  17. use Shopware\Core\Framework\Routing\Annotation\Since;
  18. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  19. use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
  20. use Shopware\Core\PlatformRequest;
  21. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceInterface;
  22. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceParameters;
  23. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  24. use Shopware\Storefront\Checkout\Cart\SalesChannel\StorefrontCartFacade;
  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 Shopware\Storefront\Page\Account\RecoverPassword\AccountRecoverPasswordPage;
  31. use Shopware\Storefront\Page\Account\RecoverPassword\AccountRecoverPasswordPageLoadedHook;
  32. use Shopware\Storefront\Page\Account\RecoverPassword\AccountRecoverPasswordPageLoader;
  33. use Symfony\Component\HttpFoundation\Request;
  34. use Symfony\Component\HttpFoundation\Response;
  35. use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
  36. use Symfony\Component\Routing\Annotation\Route;
  37. /**
  38. * @Route(defaults={"_routeScope"={"storefront"}})
  39. *
  40. * @deprecated tag:v6.5.0 - reason:becomes-internal - Will be internal
  41. */
  42. #[Package('storefront')]
  43. class AuthController extends StorefrontController
  44. {
  45. private AccountLoginPageLoader $loginPageLoader;
  46. private AbstractSendPasswordRecoveryMailRoute $sendPasswordRecoveryMailRoute;
  47. private AbstractResetPasswordRoute $resetPasswordRoute;
  48. private AbstractLoginRoute $loginRoute;
  49. private AbstractLogoutRoute $logoutRoute;
  50. private StorefrontCartFacade $cartFacade;
  51. private AccountRecoverPasswordPageLoader $recoverPasswordPageLoader;
  52. private SalesChannelContextServiceInterface $salesChannelContext;
  53. /**
  54. * @internal
  55. */
  56. public function __construct(
  57. AccountLoginPageLoader $loginPageLoader,
  58. AbstractSendPasswordRecoveryMailRoute $sendPasswordRecoveryMailRoute,
  59. AbstractResetPasswordRoute $resetPasswordRoute,
  60. AbstractLoginRoute $loginRoute,
  61. AbstractLogoutRoute $logoutRoute,
  62. StorefrontCartFacade $cartFacade,
  63. AccountRecoverPasswordPageLoader $recoverPasswordPageLoader,
  64. SalesChannelContextServiceInterface $salesChannelContextService
  65. ) {
  66. $this->loginPageLoader = $loginPageLoader;
  67. $this->sendPasswordRecoveryMailRoute = $sendPasswordRecoveryMailRoute;
  68. $this->resetPasswordRoute = $resetPasswordRoute;
  69. $this->loginRoute = $loginRoute;
  70. $this->logoutRoute = $logoutRoute;
  71. $this->cartFacade = $cartFacade;
  72. $this->recoverPasswordPageLoader = $recoverPasswordPageLoader;
  73. $this->salesChannelContext = $salesChannelContextService;
  74. }
  75. /**
  76. * @Since("6.0.0.0")
  77. * @Route("/account/login", name="frontend.account.login.page", methods={"GET"})
  78. * @NoStore
  79. */
  80. public function loginPage(Request $request, RequestDataBag $data, SalesChannelContext $context): Response
  81. {
  82. /** @var string $redirect */
  83. $redirect = $request->get('redirectTo', 'frontend.account.home.page');
  84. $customer = $context->getCustomer();
  85. if ($customer !== null && $customer->getGuest() === false) {
  86. $request->request->set('redirectTo', $redirect);
  87. return $this->createActionResponse($request);
  88. }
  89. $page = $this->loginPageLoader->load($request, $context);
  90. $this->hook(new AccountLoginPageLoadedHook($page, $context));
  91. return $this->renderStorefront('@Storefront/storefront/page/account/register/index.html.twig', [
  92. 'redirectTo' => $redirect,
  93. 'redirectParameters' => $request->get('redirectParameters', json_encode([])),
  94. 'page' => $page,
  95. 'loginError' => (bool) $request->get('loginError'),
  96. 'waitTime' => $request->get('waitTime'),
  97. 'errorSnippet' => $request->get('errorSnippet'),
  98. 'data' => $data,
  99. ]);
  100. }
  101. /**
  102. * @Since("6.3.4.1")
  103. * @Route("/account/guest/login", name="frontend.account.guest.login.page", methods={"GET"})
  104. * @NoStore
  105. */
  106. public function guestLoginPage(Request $request, SalesChannelContext $context): Response
  107. {
  108. /** @var string $redirect */
  109. $redirect = $request->get('redirectTo', 'frontend.account.home.page');
  110. $customer = $context->getCustomer();
  111. if ($customer !== null) {
  112. $request->request->set('redirectTo', $redirect);
  113. return $this->createActionResponse($request);
  114. }
  115. $waitTime = (int) $request->get('waitTime');
  116. if ($waitTime) {
  117. $this->addFlash(self::INFO, $this->trans('account.loginThrottled', ['%seconds%' => $waitTime]));
  118. }
  119. if ((bool) $request->get('loginError')) {
  120. $this->addFlash(self::DANGER, $this->trans('account.orderGuestLoginWrongCredentials'));
  121. }
  122. $page = $this->loginPageLoader->load($request, $context);
  123. $this->hook(new AccountGuestLoginPageLoadedHook($page, $context));
  124. return $this->renderStorefront('@Storefront/storefront/page/account/guest-auth.html.twig', [
  125. 'redirectTo' => $redirect,
  126. 'redirectParameters' => $request->get('redirectParameters', json_encode([])),
  127. 'page' => $page,
  128. ]);
  129. }
  130. /**
  131. * @Since("6.0.0.0")
  132. * @Route("/account/logout", name="frontend.account.logout.page", methods={"GET"})
  133. */
  134. public function logout(Request $request, SalesChannelContext $context, RequestDataBag $dataBag): Response
  135. {
  136. if ($context->getCustomer() === null) {
  137. return $this->redirectToRoute('frontend.account.login.page');
  138. }
  139. try {
  140. $this->logoutRoute->logout($context, $dataBag);
  141. $this->addFlash(self::SUCCESS, $this->trans('account.logoutSucceeded'));
  142. $parameters = [];
  143. } catch (ConstraintViolationException $formViolations) {
  144. $parameters = ['formViolations' => $formViolations];
  145. }
  146. return $this->redirectToRoute('frontend.account.login.page', $parameters);
  147. }
  148. /**
  149. * @Since("6.0.0.0")
  150. * @Route("/account/login", name="frontend.account.login", methods={"POST"}, defaults={"XmlHttpRequest"=true})
  151. */
  152. public function login(Request $request, RequestDataBag $data, SalesChannelContext $context): Response
  153. {
  154. $customer = $context->getCustomer();
  155. if ($customer !== null && $customer->getGuest() === false) {
  156. return $this->createActionResponse($request);
  157. }
  158. try {
  159. $token = $this->loginRoute->login($data, $context)->getToken();
  160. $cartBeforeNewContext = $this->cartFacade->get($token, $context);
  161. $newContext = $this->salesChannelContext->get(
  162. new SalesChannelContextServiceParameters(
  163. $context->getSalesChannelId(),
  164. $token,
  165. $context->getLanguageIdChain()[0],
  166. $context->getCurrencyId(),
  167. $context->getDomainId(),
  168. $context->getContext()
  169. )
  170. );
  171. // Update the sales channel context for CacheResponseSubscriber
  172. $request->attributes->set(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT, $newContext);
  173. if (!empty($token)) {
  174. $this->addCartErrors($cartBeforeNewContext);
  175. return $this->createActionResponse($request);
  176. }
  177. } catch (BadCredentialsException | UnauthorizedHttpException | InactiveCustomerException | CustomerAuthThrottledException $e) {
  178. if ($e instanceof InactiveCustomerException) {
  179. $errorSnippet = $e->getSnippetKey();
  180. }
  181. if ($e instanceof CustomerAuthThrottledException) {
  182. $waitTime = $e->getWaitTime();
  183. }
  184. }
  185. $data->set('password', null);
  186. return $this->forwardToRoute(
  187. 'frontend.account.login.page',
  188. [
  189. 'loginError' => true,
  190. 'errorSnippet' => $errorSnippet ?? null,
  191. 'waitTime' => $waitTime ?? null,
  192. ]
  193. );
  194. }
  195. /**
  196. * @Since("6.1.0.0")
  197. * @Route("/account/recover", name="frontend.account.recover.page", methods={"GET"})
  198. */
  199. public function recoverAccountForm(Request $request, SalesChannelContext $context): Response
  200. {
  201. $page = $this->loginPageLoader->load($request, $context);
  202. return $this->renderStorefront('@Storefront/storefront/page/account/profile/recover-password.html.twig', [
  203. 'page' => $page,
  204. ]);
  205. }
  206. /**
  207. * @Since("6.1.0.0")
  208. * @Route("/account/recover", name="frontend.account.recover.request", methods={"POST"})
  209. */
  210. public function generateAccountRecovery(Request $request, RequestDataBag $data, SalesChannelContext $context): Response
  211. {
  212. try {
  213. $data->get('email')
  214. ->set('storefrontUrl', $request->attributes->get(RequestTransformer::STOREFRONT_URL));
  215. $this->sendPasswordRecoveryMailRoute->sendRecoveryMail(
  216. $data->get('email')->toRequestDataBag(),
  217. $context,
  218. false
  219. );
  220. $this->addFlash(self::SUCCESS, $this->trans('account.recoveryMailSend'));
  221. } catch (CustomerNotFoundException $e) {
  222. $this->addFlash(self::SUCCESS, $this->trans('account.recoveryMailSend'));
  223. } catch (InconsistentCriteriaIdsException $e) {
  224. $this->addFlash(self::DANGER, $this->trans('error.message-default'));
  225. } catch (RateLimitExceededException $e) {
  226. $this->addFlash(self::INFO, $this->trans('error.rateLimitExceeded', ['%seconds%' => $e->getWaitTime()]));
  227. }
  228. return $this->redirectToRoute('frontend.account.recover.page');
  229. }
  230. /**
  231. * @Since("6.1.0.0")
  232. * @Route("/account/recover/password", name="frontend.account.recover.password.page", methods={"GET"})
  233. */
  234. public function resetPasswordForm(Request $request, SalesChannelContext $context): Response
  235. {
  236. /** @deprecated tag:v6.5.0 - call to loginPageLoader and $loginPage will be removed */
  237. $loginPage = null;
  238. if (!Feature::isActive('v6.5.0.0')) {
  239. $loginPage = $this->loginPageLoader->load($request, $context);
  240. }
  241. /** @var ?string $hash */
  242. $hash = $request->get('hash');
  243. if (!$hash || !\is_string($hash)) {
  244. $this->addFlash(self::DANGER, $this->trans('account.passwordHashNotFound'));
  245. return $this->redirectToRoute('frontend.account.recover.request');
  246. }
  247. try {
  248. $page = $this->recoverPasswordPageLoader->load($request, $context, $hash);
  249. } catch (ConstraintViolationException $e) {
  250. $this->addFlash(self::DANGER, $this->trans('account.passwordHashNotFound'));
  251. return $this->redirectToRoute('frontend.account.recover.request');
  252. }
  253. $this->hook(new AccountRecoverPasswordPageLoadedHook($page, $context));
  254. if ($page->getHash() === null || $page->isHashExpired()) {
  255. $this->addFlash(self::DANGER, $this->trans('account.passwordHashNotFound'));
  256. return $this->redirectToRoute('frontend.account.recover.request');
  257. }
  258. if (Feature::isActive('v6.5.0.0')) {
  259. return $this->renderStorefront('@Storefront/storefront/page/account/profile/reset-password.html.twig', [
  260. 'page' => $page,
  261. 'formViolations' => $request->get('formViolations'),
  262. ]);
  263. }
  264. /** @deprecated tag:v6.5.0 - page will be instance of AccountRecoverPasswordPage and $hash will be moved to $page.getHash() */
  265. return $this->renderStorefront('@Storefront/storefront/page/account/profile/reset-password.html.twig', [
  266. 'page' => $loginPage,
  267. 'hash' => $hash,
  268. 'formViolations' => $request->get('formViolations'),
  269. ]);
  270. }
  271. /**
  272. * @Since("6.1.0.0")
  273. * @Route("/account/recover/password", name="frontend.account.recover.password.reset", methods={"POST"})
  274. */
  275. public function resetPassword(RequestDataBag $data, SalesChannelContext $context): Response
  276. {
  277. $hash = $data->get('password')->get('hash');
  278. try {
  279. $pw = $data->get('password');
  280. $this->resetPasswordRoute->resetPassword($pw->toRequestDataBag(), $context);
  281. $this->addFlash(self::SUCCESS, $this->trans('account.passwordChangeSuccess'));
  282. } catch (ConstraintViolationException $formViolations) {
  283. $this->addFlash(self::DANGER, $this->trans('account.passwordChangeNoSuccess'));
  284. return $this->forwardToRoute(
  285. 'frontend.account.recover.password.page',
  286. ['hash' => $hash, 'formViolations' => $formViolations, 'passwordFormViolation' => true]
  287. );
  288. } catch (CustomerNotFoundByHashException $e) {
  289. $this->addFlash(self::DANGER, $this->trans('account.passwordChangeNoSuccess'));
  290. return $this->forwardToRoute('frontend.account.recover.request');
  291. } catch (CustomerRecoveryHashExpiredException $e) {
  292. $this->addFlash(self::DANGER, $this->trans('account.passwordHashExpired'));
  293. return $this->forwardToRoute('frontend.account.recover.request');
  294. }
  295. return $this->redirectToRoute('frontend.account.profile.page');
  296. }
  297. }