Платформа API Symfony 4 и JWT: невозможно получить токен JWT - PullRequest
0 голосов
/ 17 декабря 2018

Я пытаюсь интегрировать аутентификацию JWT в мой проект платформы API.Я могу зарегистрировать пользователя, но не могу получить токен JWT от этого созданного пользователя.

При отправке запроса с помощью curl: curl -X POST -H "Content-Type: application/json" http://localhost:8000/login_check -d '{"username":"johndoe","password":"test"}'

Я получаю ошибку: Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\BadRequestHttpException: "Invalid JSON." at (...)\vendor\symfony\security-http\Firewall\UsernamePasswordJsonAuthenticationListener.php line 92

Вот мой пользовательский объект:

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiSubresource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;

/**
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 * @ApiResource(normalizationContext={"groups"={"user"}})
 * @ApiFilter(SearchFilter::class, properties={"centres.id": "exact"})
 */
class User implements UserInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Groups({"user"})
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=50)
     * @Groups({"user"})
     */
    private $username;

    /**
     * @ORM\Column(type="string", length=64)
     * @Groups({"user"})
     */
    private $password;

    /**
     * @ORM\Column(type="string", length=50, nullable=true)
     * @Groups({"user"})
     */
    private $prenom;

    /**
     * @ORM\Column(type="string", length=50, nullable=true)
     * @Groups({"user"})
     */
    private $nom;

    /**
     * @ORM\Column(type="string", length=80)
     * @Groups({"user"})
     */
    private $email;

    /**
     * @ORM\Column(type="array")
     * @Groups({"user"})
     */
    private $roles = [];

    /**
     * @ORM\Column(type="datetime", nullable=true)
     * @Groups({"user"})
     */
    private $dateNaissance;

    /**
     * @ORM\Column(type="datetime")
     * @Groups({"user"})
     */
    private $dateEnregistrement;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     * @Groups({"user"})
     */
    private $dateDernierePartie;

    /**
     * @ORM\Column(type="boolean")
     * @Groups({"user"})
     */
    private $actif;

    /**
     * @ORM\Column(type="integer")
     * @Groups({"user"})
     */
    private $niveau;

    /**
     * @ORM\Column(type="integer")
     * @Groups({"user"})
     */
    private $experience;

    /**
     * @ORM\Column(type="integer")
     * @Groups({"user"})
     */
    private $nbVictimes;

    /**
     * @ORM\Column(type="integer")
     * @Groups({"user"})
     */
    private $nbMorts;

    /**
     * @ORM\Column(type="integer", nullable=true)
     * @Groups({"user"})
     */
    private $justesse;

    /**
     * @ORM\Column(type="integer", nullable=true)
     * @Groups({"user"})
     */
    private $nbParties;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Carte", mappedBy="client")
     * @Groups({"user"})
     * @var Collection
     */
    private $cartes;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Equipe", inversedBy="joueurs")
     * @ORM\JoinColumn(nullable=true)
     * @Groups({"user"})
     */
    private $equipe;

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Centre", inversedBy="clients")
     * @ORM\JoinTable(name="users_centres")
     * @var Collection
     * @Groups({"user"})
     */
    private $centres;

    public function __construct()
    {
        $this->cartes       = new ArrayCollection();
        $this->centres      = new ArrayCollection();
        $this->actif        = true;
        $this->niveau       = 1;
        $this->experience   = 0;
        $this->nbVictimes   = 0;
        $this->nbMorts      = 0;
        $this->justesse     = 0;
        $this->nbParties    = 0;
        $this->dateEnregistrement = new \DateTime();
    }

    /**
     * @param int|null $id
     * @param string $surnom
     * @param string $email
     * @param string $password
     * @param array $roles
     * @param \DateTime|null $dateEnregistrement
     * @return User
     */
    static public function creer(
        ?int    $id = null,
        string  $surnom,
        string  $email,
        string  $password,
        array   $roles,
        ?\DateTime $dateEnregistrement = null
    )
    {
        $user = new self();

        $user->id       = $id;
        $user->username   = $surnom;
        $user->email    = $email;
        $user->password = $password;
        $user->roles    = $roles;
        $user->dateEnregistrement = $dateEnregistrement;

        return $user;
    }

    public function addCarte(Carte $carte)
    {
        if ($this->cartes->contains($carte)) {
            return;
        }
        $this->cartes->add($carte);
        $carte->setClient($this);
    }

    public function addCentre(Centre $centre)
    {
        if ($this->centres->contains($centre)) {
            return;
        }

        $this->centres->add($centre);
        //$centre->inscrireJoueur($this);
    }

    public function ajouterNbVictimes(int $nbVictimes)
    {
        $this->nbVictimes += $nbVictimes;
    }

    public function ajouterJustesse(int $justesse)
    {
        $this->justesse += $justesse;
    }

    public function diminuerJustesse(int $justesse)
    {
        $this->justesse -= $justesse;
    }

    public function ajouterNbMorts(int $nbMorts)
    {
        $this->nbMorts += $nbMorts;
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function setUsername(string $username): self
    {
        $this->username = $username;

        return $this;
    }

    public function getPassword(): ?string
    {
        return $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    public function getPrenom(): ?string
    {
        return $this->prenom;
    }

    public function setPrenom(string $prenom): self
    {
        $this->prenom = $prenom;

        return $this;
    }

    public function getNom(): ?string
    {
        return $this->nom;
    }

    public function setNom(string $nom): self
    {
        $this->nom = $nom;

        return $this;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;

        return $this;
    }

    public function getRoles(): ?array
    {
        return $this->roles;
    }

    public function setRoles(array $roles): self
    {
        $this->roles = $roles;

        return $this;
    }

    public function getDateNaissance(): ?\DateTimeInterface
    {
        return $this->dateNaissance;
    }

    public function setDateNaissance(\DateTimeInterface $dateNaissance): self
    {
        $this->dateNaissance = $dateNaissance;

        return $this;
    }

    public function getDateEnregistrement(): ?\DateTimeInterface
    {
        return $this->dateEnregistrement;
    }

    public function setDateEnregistrement(\DateTimeInterface $dateEnregistrement): self
    {
        $this->dateEnregistrement = $dateEnregistrement;

        return $this;
    }

    public function getDateDernierePartie(): ?\DateTimeInterface
    {
        return $this->dateDernierePartie;
    }

    public function setDateDernierePartie(?\DateTimeInterface $dateDernierePartie): self
    {
        $this->dateDernierePartie = $dateDernierePartie;

        return $this;
    }

    public function getActif(): ?bool
    {
        return $this->actif;
    }

    public function setActif(bool $actif): self
    {
        $this->actif = $actif;

        return $this;
    }

    public function getNiveau(): ?int
    {
        return $this->niveau;
    }

    public function setNiveau(int $niveau): self
    {
        $this->niveau = $niveau;

        return $this;
    }

    public function getExperience(): ?int
    {
        return $this->experience;
    }

    public function setExperience(int $experience): self
    {
        $this->experience = $experience;

        return $this;
    }

    public function getNbVictimes(): ?int
    {
        return $this->nbVictimes;
    }

    public function setNbVictimes(int $nbVictimes): self
    {
        $this->nbVictimes = $nbVictimes;

        return $this;
    }

    public function getNbMorts(): ?int
    {
        return $this->nbMorts;
    }

    public function setNbMorts(int $nbMorts): self
    {
        $this->nbMorts = $nbMorts;

        return $this;
    }

    public function getJustesse(): ?int
    {
        return $this->justesse;
    }

    public function setJustesse(int $justesse): self
    {
        $this->justesse = $justesse;

        return $this;
    }

    /**
     * @return mixed
     */
    public function getNbParties()
    {
        return $this->nbParties;
    }

    /**
     * @param mixed $nbParties
     */
    public function setNbParties($nbParties): void
    {
        $this->nbParties = $nbParties;
    }

    /**
     * @return mixed
     */
    public function getCartes()
    {
        return $this->cartes;
    }

    /**
     * @param mixed $cartes
     */
    public function setCartes($cartes): void
    {
        $this->cartes = $cartes;
    }

    /**
     * @return mixed
     */
    public function getEquipe()
    {
        return $this->equipe;
    }

    /**
     * @param mixed $equipe
     */
    public function setEquipe($equipe): void
    {
        $this->equipe = $equipe;
    }

    /**
     * @return mixed
     */
    public function getCentres()
    {
        return $this->centres;
    }

    /**
     * @param mixed $centre
     */
    public function setCentres($centres): void
    {
        $this->centres = $centres;
    }

    /**
     * Returns the salt that was originally used to encode the password.
     *
     * This can return null if the password was not encoded using a salt.
     *
     * @return string|null The salt
     */
    public function getSalt()
    {
        return null;
    }

    /**
     * Returns the username used to authenticate the user.
     *
     * @return string The username
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * Removes sensitive data from the user.
     *
     * This is important if, at any given point, sensitive information like
     * the plain-text password is stored on this object.
     */
    public function eraseCredentials()
    {
    }


}

Мои маршруты.yaml:

register:
    path: /register
    controller: App\Controller\AuthController::register
    methods: POST

api:
    path: /api
    controller: App\Controller\AuthController::api

login_check:
    path:     /login_check
    methods:  [POST]

Мой AuthController:

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use App\Entity\User;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

class AuthController extends AbstractController
{
    public function register(Request $request, UserPasswordEncoderInterface $encoder)
    {
        $em = $this->getDoctrine()->getManager();

        $username = $request->request->get('_username');
        $password = $request->request->get('_password');

        $user = new User();
        $user->setUsername($username);
        $user->setEmail('');
        $user->setPassword($encoder->encodePassword($user, $password));
        $em->persist($user);
        $em->flush();

        return new Response(sprintf('User %s successfully created', $user->getUsername()));
    }

    public function api()
    {
        return new Response(sprintf('Logged in as %s', $this->getUser()->getUsername()));
    }
}

Мой security.yaml:

security:
    encoders:
        App\Entity\User:
            algorithm: bcrypt
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        entity_provider:
            entity:
                class: App\Entity\User
                property: username
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
#        main:
#            anonymous: true
        login:
            pattern:  ^/login
            stateless: true
            anonymous: true
            json_login:
                check_path: /login_check
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure

        register:
            pattern:  ^/register
            stateless: true
            anonymous: true

        api:
            pattern:  ^/api
            stateless: true
            anonymous: false
            provider: entity_provider
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator

            # activate different ways to authenticate

            # http_basic: true
            # https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate

            # form_login: true
            # https://symfony.com/doc/current/security/form_login_setup.html

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

Мой lexik_jwt_authentication.yaml:

lexik_jwt_authentication:
    secret_key: '%env(resolve:JWT_SECRET_KEY)%'
    public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
    pass_phrase: '%env(JWT_PASSPHRASE)%'

Мой файл .env:

# This file defines all environment variables that the application needs.
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE.
# Use ".env.local" for local overrides during development.
# Use real environment variables when deploying to production.
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration

###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=0c700431af8a1ffea2c6a6636dda0d4e
#TRUSTED_PROXIES=127.0.0.1,127.0.0.2
#TRUSTED_HOSTS='^localhost|example\.com$'
###< symfony/framework-bundle ###

###> nelmio/cors-bundle ###
CORS_ALLOW_ORIGIN=^https?://localhost(:[0-9]+)?$
###< nelmio/cors-bundle ###

###> doctrine/doctrine-bundle ###
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
# Configure your db driver and server_version in config/packages/doctrine.yaml
DATABASE_URL=mysql://root:@127.0.0.1:3306/my_db_name
###< doctrine/doctrine-bundle ###

###> lexik/jwt-authentication-bundle ###
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=8cc34a18525a9c1c338424443bbdd185
###< lexik/jwt-authentication-bundle ###

Возможно, я что-то не так делаю,спасибо за помощь.

Ответы [ 2 ]

0 голосов
/ 25 марта 2019

С помощью cmder для отправки действительного json это должно быть так:

curl -X POST -H "Content-Type: application/json" http://localhost:8000/login_check -d "{\"username\":\"johndoe\",\"password\":\"test\"}"
0 голосов
/ 19 декабря 2018

Проблема в том, что я на Windows и использую cmder, который, кажется, не ясно отправляет JSON.Я сделал запрос у Почтальона и получил токен, который хотел.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...