Вчера мы увидели, как защитить наш API с помощью токена и как использовать токен в VueJs. Сегодня мы увидим, как аутентифицировать пользователя в нашем приложении в контексте SPA с помощью VueJS .

Продолжим шаг за шагом.

1. Безопасность с Symfony

A) Создать объект пользователя

<?php
namespace App\Entity;
...
/**
 * @ApiResource(
 *     itemOperations={
 *          "get"={
 *             "path"="/users/{id}",
 *             "swagger_context"={
 *                 "tags"={"Account"}
 *             }
 *          }
 *     },
 *     collectionOperations={
 *         "post"={
 *             "path"="/users",
 *             "method"="POST",
 *             "swagger_context"={
 *                 "tags"={"Account"},
 *                 "summary"={"Create a new account"}
 *             }
 *         },
 *         "get"={
 *             "path"="/users",
 *             "method"="GET",
 *             "swagger_context"={
 *                 "tags"={"Account"}
 *             }
 *          }
 *     },
 * )
 *
 * @ORM\Entity(repositoryClass="App\Repository\UserAccountRepository")
 */
final class UserAccount implements UserInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;
    /**
     * @ORM\Column(type="string", length=180)
     */
    private $firstName;
    /**
     * @ORM\Column(type="string", length=180)
     */
    private $lastName;
    /**
     * @ORM\Column(type="string", length=180, unique=true)
     */
    private $email;
    /**
     * @ORM\Column(type="json")
     */
    private $roles = [];
    /**
     * @var string The hashed password
     * @ORM\Column(type="string")
     */
    private $password;
    /**
     * @ORM\Column(type="string", unique=true, nullable=true)
     */
    private $apiToken;
    public function getId(): ?int
    {
        return $this->id;
    }
    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUsername(): string
    {
        return (string)$this->email;
    }
    public function getEmail(): string
    {
        return (string)$this->email;
    }
    public function setEmail(string $email): self
    {
        $this->email = $email;
        return $this;
    }
    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';
        return array_unique($roles);
    }
    public function setRoles(array $roles): self
    {
        $this->roles = $roles;
        return $this;
    }
    /**
     * @see UserInterface
     */
    public function getPassword(): string
    {
        return (string)$this->password;
    }
    public function setPassword(string $password): self
    {
        $this->password = $password;
        return $this;
    }
    /**
     * @see UserInterface
     */
    public function getSalt()
    {
        // not needed when using the "bcrypt" algorithm in security.yaml
    }
    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }
    public function getApiToken(): ?string
    {
        return $this->apiToken;
    }
    public function setApiToken($apiToken): void
    {
        $this->apiToken = $apiToken;
    }
    public function getFirstName()
    {
        return $this->firstName;
    }
    public function setFirstName($firstName): void
    {
        $this->firstName = $firstName;
    }
    public function getLastName()
    {
        return $this->lastName;
    }
    public function setLastName($lastName): void
    {
        $this->lastName = $lastName;
    }
}

Б) Создать аутентификатор

<?php
namespace App\Security;
...
class JsonAuthenticator extends AbstractFormLoginAuthenticator
{
    use TargetPathTrait;
    private $entityManager;
    private $router;
    private $csrfTokenManager;
    private $passwordEncoder;
    public function __construct(
        EntityManagerInterface $entityManager,
        RouterInterface $router,
        CsrfTokenManagerInterface $csrfTokenManager,
        UserPasswordEncoderInterface $passwordEncoder
    ) {
        $this->entityManager = $entityManager;
        $this->router = $router;
        $this->csrfTokenManager = $csrfTokenManager;
        $this->passwordEncoder = $passwordEncoder;
    }
    public function supports(Request $request)
    {
        return 'app_account' === $request->attributes->get('_route')
            && $request->isMethod('POST');
    }
    public function getCredentials(Request $request)
    {
        if ($request->getContentType() !== 'json') {
            throw new BadRequestHttpException();
        }
        $data = json_decode($request->getContent(), true);
        $credentials = [
            'email' => $data['email'],
            'password' => $data['password'],
            'csrf_token' => $data['_csrf_token'],
        ];
        $request->getSession()->set(
            Security::LAST_USERNAME,
            $credentials['email']
        );
        return $credentials;
    }
    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        $token = new CsrfToken('authenticate', $credentials['csrf_token']);
        if (!$this->csrfTokenManager->isTokenValid($token)) {
            throw new InvalidCsrfTokenException();
        }
        $user = $this->entityManager->getRepository(UserAccount::class)->findOneBy(['email' => $credentials['email']]);
        if (!$user) {
            // fail authentication with a custom error
            throw new CustomUserMessageAuthenticationException('Email could not be found.');
        }
        return $user;
    }
    public function checkCredentials($credentials, UserInterface $user)
    {
        return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
    }
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        return new JsonResponse($exception->getMessage());
    }
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }
        return new JsonResponse('authenticated');
    }
}

Продолжить чтение: https://stefanoalletti.wordpress.com/2019/08/05/authentication-with-vuejs-using-symfony-and-api-platform-part-2/