Pour l'instant, notre application n'a pas d'identification. On souhaite maintenant ajouter des utilisateurs, leur permettre de s'inscrire à travers l'API, puis de se connecter.
Certaines requêtes de l'API nécessiteront un compte par la suite.
Tout d'abord, ajoutez une entité utilisateur :
symfony console make:user
Mettez en suite à jour le schéma de la base de données :
symfony console doctrine:schema:update --force
Créez ensuite un formulaire d'inscription, il nous servira d'exemple pour créer l'équivalent en version "API" (Attention: répondez "no" à la question vous demandant d'envoyer un e-mail):
symfony console make:registration
Il est désormais possible de s'inscrire via la route /register
à l'aide d'une adresse e-mail et d'un mot
de passe. Ajoutez un endpoint dans l'API :
/api/register
POST
Vous pourrez fonctionner de la même manière que POST /api/message
. Inspirez vous du contenu du
RegistrationController
, notamment pour hasher le mot de passe.
Les erreurs (par exemple, si l'e-mail n'est pas renseignée ou déjà utilisée) doivent remonter à travers l'API également.
Note: À l'aide des tags, vous pouvez commencer à regrouper les mots d'API par section comme cela:
Nous allons authentifier nos utilisateurs à l'aide d'un jeton. Pour cela, utilisez :
symfony console make:entity
Pour ajouter un champ token
dans l'entité User
de type string
nullable.
N'oubliez pas de répercuter le changement dans la base à l'aide de :
symfony console doctrine:schema:update --force
Modifier votre inscription afin que le jeton soit généré aléatoirement et stocké dans la base de données.
À l'aide de la documentation officielle,
créez maintenant un endpoint /api/login
, qui permettra de distribuer le jeton.
Voici à quoi pourrait ressembler le endpoint
#[View()]
#[Route('/login', methods: ['POST'], name: "api_login")]
#[OA\Post(summary: "Login",tags: ["User"])]
#[OA\RequestBody(content:
new OA\JsonContent(
example: '{"username": "user@user.com", "password": "password"}'
))]
public function login(#[CurrentUser()] User $user)
{
return $user->getToken();
}
Testez votre endpoint de connexion à l'aide d'un compte utilisateur inscrit.
Modifiez config/packages/security.yaml
, pour ajouter :
security:
# ...
firewalls:
# ...
main:
stateless: true
access_token:
token_handler: App\Security\AccessTokenHandler
# ...
Placez ensuite le contenu suivant dans src/Security/AccessTokenHandler.php
(source: documentation officielle):
<?php
// src/Security/AccessTokenHandler.php
namespace App\Security;
use App\Repository\UserRepository;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
class AccessTokenHandler implements AccessTokenHandlerInterface
{
public function __construct(
private UserRepository $repository
) {
}
public function getUserBadgeFrom(string $accessToken): UserBadge
{
$user = $this->repository->findOneBy(["token" => $accessToken]);
if (null === $user) {
throw new BadCredentialsException('Invalid credentials.');
}
return new UserBadge($user->getUserIdentifier());
}
}
Ajoutez à la section components
de nelmio_api_doc.yaml
:
securitySchemes:
Bearer:
type: http
scheme: bearer
Vous pouvez désormais ajouter les attributs suivants à POST /api/message
:
// Provient de Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted
#[IsGranted("ROLE_USER")]
// Provient de Nelmio\ApiDocBundle\Annotation\Security;
#[Security(name: "Bearer")]
Vous devriez maintenant voir apparaître un cadenas indiquant que la route nécessite l'identification, et un bouton en haut à droite permettant de s'identifier :
Utilisez à nouveau symfony console make:entity
pour ajouter un champ user
de type ManyToOne
de Message
vers User
.
POST /api/message
de manière à ce que l'utilisateur courant soit associé au messagemessage_basic
(à chaque fois qu'un message est récupéré, on
pourra voir son e-mail)Faites en sorte que PATCH
et DELETE
ne fonctionnent pas si l'utilisateur n'est pas identifié, et n'est
pas propriétaire du message
Ajoutez l'utilisateur au groupe message_basic
, de manière à ce que l'utilisateur apparaisse dans la recherche
des messages.