読み込みが終了しない場合は、しばらく待つか、リロードを行なってください。
If loading does not finish, wait for a while or reload.
エンジニア向けの情報を発信するブログです。
どなたでも発信できます。
お好きに利用していただれば幸いです。
📁 ec-cube/app/Customize/Form/Extension/Front/CustomerLoginTypeExtension.php <?php namespace Customize\Form\Extension\Front; use Eccube\Form\Type\Front\CustomerLoginType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\Type\TextType; class CustomerLoginTypeExtension extends AbstractTypeExtension { /** * {@inheritdoc} */ public static function getExtendedTypes() { return [CustomerLoginType::class]; } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add( 'two_factor_token', TextType::class, [ 'mapped' => false, ] ); } }
📁 ec-cube/app/Customize/Controller/Mypage/LoginController.php <?php namespace Customize\Controller\Mypage; use Eccube\Controller\AbstractController; use Eccube\Entity\Customer; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Eccube\Repository\CustomerRepository; use Eccube\Repository\Master\CustomerStatusRepository; use Eccube\Entity\Master\CustomerStatus; use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use Eccube\Repository\BaseInfoRepository; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Validator\Constraints as Assert; class LoginController extends AbstractController { private $customerRepository; private $customerStatusRepository; private $encoderFactory; private $mailer; private $baseInfoRepository; private $validator; public function __construct( CustomerRepository $customerRepository, CustomerStatusRepository $customerStatusRepository, EncoderFactoryInterface $encoderFactory, \Swift_Mailer $mailer, BaseInfoRepository $baseInfoRepository, ValidatorInterface $validator ) { $this->customerRepository = $customerRepository; $this->customerStatusRepository = $customerStatusRepository; $this->encoderFactory = $encoderFactory; $this->mailer = $mailer; $this->baseInfoRepository = $baseInfoRepository; $this->validator = $validator; } /** * @param Request $request * @Route("/check/customer/password", name="check_customer_password", methods={"POST"}) */ public function checkCustomerPassword(Request $request) { if (!$request->isXmlHttpRequest()) { return $this->json(['status' => 'NG'], 400); } $this->isTokenValid(); $login_email = $request->get('login_email'); $login_pass = $request->get('login_pass'); if (!isset($login_email, $login_pass)) { return $this->json(['status' => 'NG'], 500); } $customer = $this->customerRepository->findOneBy( [ 'email' => $login_email, 'Status' => $this->customerStatusRepository->find(CustomerStatus::REGULAR), ] ); if (!$customer instanceof Customer) { return $this->json(['status' => 'NG'], 500); } $encoder = $this->encoderFactory->getEncoder($customer); if ($encoder->isPasswordValid($customer->getPassword(), $login_pass, $customer->getSalt())) { $token = mt_rand(100000,999999); $base_info = $this->baseInfoRepository->get(); $message = (new \Swift_Message()) ->setSubject('トークンの送信') ->setFrom([$base_info->getEmail01() => $base_info->getShopName()]) ->setTo([$customer->getEmail()]) ->setBody($token); $this->session->set('login_token', $token); $count = $this->mailer->send($message, $failures); return $this->json(['status' => 'OK']); } return $this->json(['status' => 'NG'], 500); } /** * @param Request $request * @return \Symfony\Component\HttpFoundation\RedirectResponse * @Route("/check/customer/token", name="check_customer_token", methods={"POST"}) */ public function login(Request $request) { $token = $request->get('two_factor_token'); $errors = $this->validator->validate( $token, [ new Assert\NotBlank(), new Assert\Type(['type' => 'numeric']), ] ); if ($errors->count() === 0 && $token === (string)$this->session->get('login_token')) { $this->session->remove('login_token'); return $this->redirectToRoute( 'mypage_login', [ 'request' => $request ], 307 ); } $this->session->remove('login_token'); $this->session->getFlashBag()->set('bad_flash', 'ばーかちゃんとしろばか'); return $this->redirectToRoute( 'mypage_login', [ 'request' => $request, ] ); } }
/** * @param Request $request * @Route("/check/customer/password", name="check_customer_password", methods={"POST"}) */ public function checkCustomerPassword(Request $request) { // ajaxの通信かバリデート if (!$request->isXmlHttpRequest()) { return $this->json(['status' => 'NG'], 400); } // csrf_tokenのバリデート $this->isTokenValid(); // requestから入力されたemailとpasswordを取得 $login_email = $request->get('login_email'); $login_pass = $request->get('login_pass'); // emailとpasswordどちらもparameterがあるかのばりデート if (!isset($login_email, $login_pass)) { return $this->json(['status' => 'NG'], 500); } // emailから本会員登録されているcustomerがいるか検索 $customer = $this->customerRepository->findOneBy( [ 'email' => $login_email, 'Status' => $this->customerStatusRepository->find(CustomerStatus::REGULAR), ] ); // customerがいるかのバリデート if (!$customer instanceof Customer) { return $this->json(['status' => 'NG'], 500); } // encoderなるものを取得 $encoder = $this->encoderFactory->getEncoder($customer); // customerのpasswordがあっているか判定 if ($encoder->isPasswordValid($customer->getPassword(), $login_pass, $customer->getSalt())) { // tokenを生成 $token = mt_rand(100000,999999); // eccubeの設定を取得 $base_info = $this->baseInfoRepository->get(); // mailerを設定 $message = (new \Swift_Message()) ->setSubject('トークンの送信') ->setFrom([$base_info->getEmail01() => $base_info->getShopName()]) ->setTo([$customer->getEmail()]) // mailの本文に生成したtokenをセット ->setBody($token); // sessionにtokenをセット $this->session->set('login_token', $token); // mail送信 $count = $this->mailer->send($message, $failures); // 成功ステータスを返す return $this->json(['status' => 'OK']); } return $this->json(['status' => 'NG'], 500); }
/** * @param Request $request * @return \Symfony\Component\HttpFoundation\RedirectResponse * @Route("/check/customer/token", name="check_customer_token", methods={"POST"}) */ public function login(Request $request) { // トークンを取得 $token = $request->get('two_factor_token'); // 必須,数字バリデーション $errors = $this->validator->validate( $token, [ new Assert\NotBlank(), new Assert\Type(['type' => 'numeric']), ] ); // バリデーションを突破かつ送信されたトークンとセッションのトークンが同じなら if ($errors->count() === 0 && $token === (string)$this->session->get('login_token')) { // もうセッションのトークンは不要なので削除する $this->session->remove('login_token'); // デフォルトのログインアクションにpostとしてリダイレクト return $this->redirectToRoute( 'mypage_login', [ 'request' => $request ], 307 // <- こうするとpostでリダイレクトできる ); } // ダメだったら、セッションのトークンを削除 $this->session->remove('login_token'); // 適当にダメでしたフラッシュをセット $this->session->getFlashBag()->set('bad_flash', 'ばーかちゃんとしろばか'); // デフォルトのログインアクションにリダイレクト return $this->redirectToRoute( 'mypage_login', [ 'request' => $request, ] ); }
📁 ec-cube/app/template/default/Mypage/login.twig {# This file is part of EC-CUBE Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved. http://www.ec-cube.co.jp/ For the full copyright and license information, please view the LICENSE file that was distributed with this source code. #} {% extends 'default_frame.twig' %} {% set body_class = 'mypage' %} {% block main %} {# jsを追加 #} <script> $(function () { {# トークン送信ボタンを押したら #} $('#send_token').on('click', function () { {# emailとpasswordのフォームの値を取得 #} let login_email_value = $('#login_email').val(); let login_pass_value = $('#login_pass').val(); {# 値があったら #} if (login_email_value.length && login_pass_value.length) { {# ajaxでpassword判定アクションにリクエストを送信 #} $.ajax({ url: '{{ url('check_customer_password') }}', type: 'POST', data: { 'login_email': login_email_value, 'login_pass': login_pass_value, }, dataType: 'json', }).done(function (data) { {# 成功したらトークンの入力を促す #} $('.ec-icon').after(`<span style="color: green">トークンプリーズ</span>`); }).fail(function (data) { {# ダメだったら煽る #} $('.ec-icon').after(`<span style="color: red">ばーかばーか帰ればか</span>`); }); } }); }); </script> <div class="ec-role"> {# ログイン失敗時のフラッシュがあれば表示 #} {% if app.session.flashBag.has('bad_flash') %} <div class="alert alert-danger" role="alert"> {% for message in app.session.flashBag.get('bad_flash') %} {{ message }} {% endfor %} </div> {% endif %} <div class="ec-pageHeader"> <h1>{{ 'ログイン'|trans }}</h1> </div> <div class="ec-off2Grid"> <div class="ec-off2Grid__cell"> {# 送信先を変更 #} <form name="login_mypage" id="login_mypage" method="post" action="{{ url('check_customer_token') }}"> {% if app.session.flashBag.has('eccube.login.target.path') %} {% for targetPath in app.session.flashBag.peek('eccube.login.target.path') %} <input type="hidden" name="_target_path" value="{{ targetPath }}" /> {% endfor %} {% endif %} <div class="ec-login"> <div class="ec-login__icon"> <div class="ec-icon"><img src="{{ asset('assets/icon/user.svg') }}" alt=""></div> </div> <div class="ec-login__input"> <div class="ec-input"> {{ form_widget(form.login_email, {'attr': {'style' : 'ime-mode: disabled;', 'placeholder' : 'メールアドレス', 'autofocus': true}}) }} {{ form_widget(form.login_pass, {'attr': {'placeholder' : 'パスワード' }}) }} {# トークンフォーム追加 #} {{ form_widget(form.two_factor_token, {'attr': {'placeholder' : 'トークン' }}) }} </div> {% if BaseInfo.option_remember_me %} <div class="ec-checkbox"> <label> {% if is_granted('IS_AUTHENTICATED_REMEMBERED') %} <input type="hidden" name="login_memory" value="1"> {% else %} {{ form_widget(form.login_memory, { 'label': '次回から自動的にログインする'|trans }) }} {% endif %} </label> </div> {% endif %} {% for reset_complete in app.session.flashbag.get('password_reset_complete') %} <p>{{ reset_complete|trans }}</p> {% endfor %} {% if error %} <p class="ec-errorMessage">{{ error.messageKey|trans(error.messageData, 'validators')|nl2br }}</p> {% endif %} </div> <div class="ec-grid2"> <div class="ec-grid2__cell"> <div class="ec-login__actions"> <button type="submit" class="ec-blockBtn--cancel">{{ 'ログイン'|trans }}</button> {# トークン送信ボタン追加 #} <button type="button" class="ec-blockBtn--cancel" id="send_token">トークン送信</button> </div> </div> <div class="ec-grid2__cell"> <div class="ec-login__link"><a class="ec-link" href="{{ url('forgot') }}">{{ 'ログイン情報をお忘れですか?'|trans }}</a> </div> <div class="ec-login__link"><a class="ec-link" href="{{ url('entry') }}">{{ '新規会員登録'|trans }}</a> </div> </div> </div> </div> <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"> </form> </div> </div> </div> {% endblock %}