<?php
/*
* 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.
*/
namespace Customize\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Doctrine\ORM\EntityManagerInterface;
use Customize\Entity\LoggedinHistory;
use Eccube\Entity\Customer;
use Exception;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* コントローラを呼び出す直前のイベントリスナー。
* コントローラに渡すパラメータなどを変更できる。
* @see https://symfony.com/doc/4.4/components/http_kernel.html#component-http-kernel-event-table
*/
class ControllerAugumentsListener implements EventSubscriberInterface
{
/**
* ログインチェックから除外するページの一覧(name)を定義する
*/
const EXCLUDE_MULTIPLE_LOGIN_PREVENTION_PAGES = array(
'mypage_login'
);
const BLOG_DETAIL = array(
'cm_blog_pro_page_list',
'cm_blog_pro_page_detail'
);
/**
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* @var SessionInterface
*/
private $session;
/**
* @var Security $security
*/
private $security;
public function __construct(EntityManagerInterface $entityManager, SessionInterface $session, Security $security)
{
$this->entityManager = $entityManager;
$this->session = $session;
$this->security = $security;
}
/**
* 対応するメソッドと優先度を登録する。
* 数値が高いほど優先度高。
*
* @see https://symfony.com/doc/4.4/event_dispatcher.html
*
* @return array
*/
public static function getSubscribedEvents()
{
return [
KernelEvents::CONTROLLER_ARGUMENTS => [
['multipleLoginPrevention', 1],
['blogDetailBlocker', 0]
]
];
}
/**
* セッションにログイントークン、データベースにユーザ情報とログイントークンを保存する。
* 一般ユーザログインとしてログイン済みで、他の端末(トークン)からのログインがあれば強制ログアウトする。
*
* @param ControllerArgumentsEvent $event
* @return RedirectResponse|void
*/
public function multipleLoginPrevention(ControllerArgumentsEvent $event)
{
global $kernel;
$container = $kernel->getContainer();
$request = $event->getRequest();
$route = $request->get('_route');
/** @var Customer|\Eccube\Entity\Member $user */
$user = $this->security->getUser();
if (!$user instanceof Customer) {
return;
}
if (in_array($route, self::EXCLUDE_MULTIPLE_LOGIN_PREVENTION_PAGES)) {
return;
}
$sessionLoginToken = $this->session->get('login_token', '');
/** @var LoggedinHistory|null $loggedinHistory */
$loggedinHistory = $this->entityManager->getRepository('\Customize\Entity\LoggedinHistory')
->findOneBy(['Customer' => $user], ['login_date' => 'DESC']);
if (empty($sessionLoginToken) || empty($loggedinHistory)) {
return;
}
$dbLoginToken = $loggedinHistory->getLoginToken();
if ($dbLoginToken != $sessionLoginToken) {
$container->get('security.token_storage')->setToken(null);
$redirectUrl = $container->get('router')->generate('mypage_login', [], UrlGeneratorInterface::ABSOLUTE_PATH);
if (empty($redirectUrl)) {
$redirectUrl = '/';
}
$this->session->getFlashBag()->add('customize.info.auto_logout', '他の画面からのログインを検知したためログアウトされました。');
$event->setController(function () use ($redirectUrl) {
return new RedirectResponse($redirectUrl);
});
}
}
/**
* 会員専用ブログにアクセスできないようデフォルトのブログ画面へのアクセスはリダイレクトさせる
*
* @param ControllerArgumentsEvent $event
* @return void
* @throws NotFoundHttpException
*/
public function blogDetailBlocker(ControllerArgumentsEvent $event)
{
$request = $event->getRequest();
$route = $request->get('_route');
if (in_array($route, self::BLOG_DETAIL)) {
throw new NotFoundHttpException();
}
}
}