トークンを使用したAPI認証

前に約束したように、Symfony2でのAPIの作成に関する一連の記事を続けます。 今日は認可についてお話したいと思います。 人気のあるバンドルのうち、JWTAuthenticationBundleとFOSOAuthServerBundleがあり、それぞれに長所と短所がありますが、どのように機能するかを理解するために自分で認証を行う方法を教えたいと思います。

最初に、ユーザーアクセストークンを格納するUserAccessTokenエンティティを作成します。

<?php namespace App\CommonBundle\Entity; use Doctrine\ORM\Mapping AS ORM; /** * @ORM\Entity * @ORM\Table(name="user_access_tokens") */ class UserAccessToken { /** * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") * @ORM\Column(name="id", type="integer") */ protected $id; /** * @ORM\ManyToOne(targetEntity="User") * @ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="SET NULL") */ protected $user; /** *      .          ,     * * @ORM\Column(name="access_token", type="string") */ protected $accessToken; /** * ,        * * @ORM\Column(name="expired_at", type="datetime") */ protected $expiredAt; /** * @ORM\Column(name="created_at", type="datetime") */ protected $createdAt; }
      
      







ここで、APIへのすべてのリクエストをリッスンし、ユーザーを認証するリスナーを作成します。



 <?php namespace App\CommonBundle\Listener; use App\CommonBundle as Common; use Doctrine\ORM\EntityManager; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; class AccessTokenListener { private $entityManager; private $securityContext; private $exclude = [ '/users/login', '/users/registration', ]; const EMPTY_ACCESS_TOKEN = 'empty_access_token'; const INVALID_ACCESS_TOKEN = 'invalid_access_token'; const ACCESS_TOKEN_EXPIRED = 'access_token_expired'; public function __construct(EntityManager $entityManager, SecurityContextInterface $securityContext) { $this->entityManager = $entityManager; $this->securityContext = $securityContext; } /** * @return Common\Entity\UserAccessToken */ private function getByAccessToken($accessToken) { return $this->entityManager->getRepository('CommonBundle:UserAccessToken')->findOneByAccessToken($accessToken); } public function beforeController(GetResponseEvent $event) { //        URL //    ,        if (in_array($event->getRequest()->getPathInfo(), $this->exclude)) { return; } //     X-Access-Token,    –   $accessToken = $event->getRequest()->headers->get('X-Access-Token'); if (!$accessToken) { $event->setResponse(new JsonResponse(['error' => self::EMPTY_ACCESS_TOKEN], 403)); return; } //       $token = $this->getByAccessToken($accessToken); if (!$token) { $event->setResponse(new JsonResponse(['error' => self::INVALID_ACCESS_TOKEN], 403)); return; } //       if ($token->getExpiredAt() <= new \DateTime('now')) { $event->setResponse(new JsonResponse(['error' => self::ACCESS_TOKEN_EXPIRED], 403)); return; } //  ,        $this->getUser() $user = $token->getUser(); $usernamePasswordToken = new UsernamePasswordToken($user, $user->getPassword(), "main", $user->getRoles()); $this->securityContext->setToken($usernamePasswordToken); } }
      
      







そして、services.ymlにプラグインします

  common.listener.access_token: class: App\CommonBundle\Listener\AccessTokenListener arguments: [@doctrine.orm.entity_manager, @security.context] tags: - { name: kernel.event_listener, event: kernel.request, method: beforeController }
      
      







これでほとんどすべてです。ユーザー名とパスワードを受け入れ、成功した場合は、生成されたaccessToken値を使用して新しいUserAccessTokenを作成し、応答で返す単純な認証方法を作成するだけです。



All Articles