Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ログアウト機能の作成。 #159

Merged
59 changes: 59 additions & 0 deletions Controller/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,16 @@
use Eccube\Controller\AbstractController;
use Eccube\Http\JsonResponse;
use Eccube\Http\Response;
use Eccube\Security\SecurityContext;
use GraphQL\Error\DebugFlag;
use GraphQL\Error\Error;
use GraphQL\GraphQL;
use League\Bundle\OAuth2ServerBundle\Manager\AccessTokenManagerInterface;
use League\Bundle\OAuth2ServerBundle\Manager\RefreshTokenManagerInterface;
use League\Bundle\OAuth2ServerBundle\Model\AccessToken;
use League\Bundle\OAuth2ServerBundle\Model\RefreshToken;
use League\Bundle\OAuth2ServerBundle\Repository\AccessTokenRepository;
use League\Bundle\OAuth2ServerBundle\Repository\RefreshTokenRepository;
use Plugin\Api42\GraphQL\Schema;
use Plugin\Api42\GraphQL\Types;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
Expand All @@ -42,15 +49,31 @@ class ApiController extends AbstractController
* @var Schema
*/
private $schema;
private SecurityContext $securityContext;
private RefreshTokenRepository $refreshTokenRepository;
private AccessTokenRepository $accessTokenRepository;
private RefreshTokenManagerInterface $refreshTokenManager;
private AccessTokenManagerInterface $accessTokenManager;

public function __construct(
Types $types,
KernelInterface $kernel,
Schema $schema,
SecurityContext $securityContext,
RefreshTokenRepository $refreshTokenRepository,
AccessTokenRepository $accessTokenRepository,
RefreshTokenManagerInterface $refreshTokenManager,
AccessTokenManagerInterface $accessTokenManager
) {
$this->types = $types;
$this->kernel = $kernel;
$this->schema = $schema;
$this->securityContext = $securityContext;
$this->refreshTokenRepository = $refreshTokenRepository;

$this->accessTokenRepository = $accessTokenRepository;
$this->refreshTokenManager = $refreshTokenManager;
$this->accessTokenManager = $accessTokenManager;
}

/**
Expand Down Expand Up @@ -108,4 +131,40 @@ public function index(Request $request)

return $jsonResult;
}

/**
* ログアウトしてOAuth2のセッションを無効化する.
* @Route("/api/logout", name="api_logout", methods={"POST", "OPTIONS"})
*/
public function logoutAndInvalidateOAuth2Session(): JsonResponse
{
$user = $this->securityContext->getLoginUser();
if ($user !== null) {
/** @var AccessToken[]|null $tokenList */
$tokenList = $this->entityManager->getRepository(AccessToken::class)->findBy(['userIdentifier' => $user->getUsername()]);
foreach ($tokenList as $tokenRow) {
$refreshTokenList = $this->entityManager->getRepository(RefreshToken::class)->findBy(['accessToken' => $tokenRow->getIdentifier()]);
foreach ($refreshTokenList as $refreshTokenRow) {
// ユーザーのリフレッシュトークンを削除
$this->refreshTokenRepository->revokeRefreshToken($refreshTokenRow->getIdentifier());
$this->entityManager->flush();
}

// ユーザーのアクセストークンを削除
$this->accessTokenRepository->revokeAccessToken($tokenRow->getIdentifier());
$this->entityManager->flush();
}
} else {
log_alert('IGNORED, NO ACTIVE USER');
}

// 他の有効期限切れたトークンを削除
$this->accessTokenManager->clearExpired();
$this->refreshTokenManager->clearExpired();

$jsonResponse = new JsonResponse();
$jsonResponse->setContent(json_encode(['message' => 'success']));

return $jsonResponse;
}
}
8 changes: 8 additions & 0 deletions DependencyInjection/ApiExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ public function prepend(ContainerBuilder $container)
foreach ($names as $name) {
// adminの前にapiを追加する
if ($name === 'admin') {
// ログアウトの設定を追加
$replaced['api_logout'] = [
'pattern' => '^/api/logout',
'security' => true,
'stateless' => true,
'oauth2' => true,
'provider' => 'user_provider'
];
$replaced['api'] = [
'pattern' => '^/api',
'security' => true,
Expand Down
13 changes: 11 additions & 2 deletions Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace Plugin\Api42;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

Expand All @@ -29,19 +30,27 @@ public static function getSubscribedEvents()
{
return [
KernelEvents::RESPONSE => 'onKernelResponse',
KernelEvents::EXCEPTION => 'onKernelResponse',
];
}

/**
* OPTIONメソッドの場合は、処理を中断する.
*
* @param ExceptionEvent|ResponseEvent $event
*
* @return void
*/
public function onKernelResponse(ResponseEvent $event)
public function onKernelResponse(ExceptionEvent|ResponseEvent $event): void
{
$request = $event->getRequest();
if ($request->getMethod() === 'OPTIONS' || $request->getMethod() === 'POST' && ($request->attributes->get('_route') === 'oauth2_token' || $request->attributes->get('_route') === 'oauth2_authorize') || $request->attributes->get('_route') === 'api') {
if ($request->getMethod() === 'OPTIONS' || $request->getMethod() === 'POST' && ($request->attributes->get('_route') === 'oauth2_token' || $request->attributes->get('_route') === 'api_logout' || $request->attributes->get('_route') === 'oauth2_authorize') || $request->attributes->get('_route') === 'api') {

$response = $event->getResponse();
if ($response === null) {
return;
}

$response->headers->add([
'Access-Control-Allow-Origin' => '*',
'Content-Type' => 'application/json',
Expand Down
Loading