Question

Créez une nouvelle API en utilisant Symfony (ou re-utilisez celle créée avec les chapitres 1 et 2). Cette API devra posséder au moins une ressource Article, avec un id, un titre et un contenu. Des points d'API devront être implémentés afin de pouvoir créer, modifier, supprimer et afficher un ou plusieurs articles à la demande d'un client.

En utilisant les informations et exemples de code présentés, sécurisez ensuite votre API en utilisant le mécanisme de JWT via le bundle Lexic Authentication JWT. Vérifier enfin que votre API est correctement sécurisée en utilisant Postman.

Solution

Entité User
1
<?php
2
3
namespace App\Entity;
4
5
use App\Repository\UserRepository;
6
use Doctrine\ORM\Mapping as ORM;
7
use Symfony\Component\Security\Core\User\UserInterface;
8
9
/**
10
 * @ORM\Entity(repositoryClass=UserRepository::class)
11
 */
12
class User implements UserInterface
13
{
14
    /**
15
     * @ORM\Id
16
     * @ORM\GeneratedValue
17
     * @ORM\Column(type="integer")
18
     */
19
    private $id;
20
21
    /**
22
     * @ORM\Column(type="string", length=180, unique=true)
23
     */
24
    private $username;
25
26
    /**
27
     * @ORM\Column(type="json")
28
     */
29
    private $roles = [];
30
31
    /**
32
     * @var string The hashed password
33
     * @ORM\Column(type="string")
34
     */
35
    private $password;
36
37
    public function getId(): ?int
38
    {
39
        return $this->id;
40
    }
41
42
    /**
43
     * A visual identifier that represents this user.
44
     *
45
     * @see UserInterface
46
     */
47
    public function getUsername(): string
48
    {
49
        return (string) $this->username;
50
    }
51
52
    public function setUsername(string $username): self
53
    {
54
        $this->username = $username;
55
56
        return $this;
57
    }
58
59
    /**
60
     * @see UserInterface
61
     */
62
    public function getRoles(): array
63
    {
64
        $roles = $this->roles;
65
        // guarantee every user at least has ROLE_USER
66
        $roles[] = 'ROLE_USER';
67
68
        return array_unique($roles);
69
    }
70
71
    public function setRoles(array $roles): self
72
    {
73
        $this->roles = $roles;
74
75
        return $this;
76
    }
77
78
    /**
79
     * @see UserInterface
80
     */
81
    public function getPassword(): string
82
    {
83
        return (string) $this->password;
84
    }
85
86
    public function setPassword(string $password): self
87
    {
88
        $this->password = $password;
89
90
        return $this;
91
    }
92
93
    /**
94
     * Returning a salt is only needed, if you are not using a modern
95
     * hashing algorithm (e.g. bcrypt or sodium) in your security.yaml.
96
     *
97
     * @see UserInterface
98
     */
99
    public function getSalt(): ?string
100
    {
101
        return null;
102
    }
103
104
    /**
105
     * @see UserInterface
106
     */
107
    public function eraseCredentials()
108
    {
109
        // If you store any temporary, sensitive data on the user, clear it here
110
        // $this->plainPassword = null;
111
    }
112
}
Variables d'environnement du fichier .env.local
1
###> lexik/jwt-authentication-bundle ###
2
3
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
4
5
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
6
7
JWT_PASSPHRASE=xxxxx
8
9
###< lexik/jwt-authentication-bundle ###
Configuration des clés du bundle Lexik JWT Authentication
1
#config/packages/lexik_jwt_authentication.yaml
2
lexik_jwt_authentication:
3
    secret_key: '%env(resolve:JWT_SECRET_KEY)%'
4
    public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
5
    pass_phrase: ‘%env(JWT_PASSPHRASE)%'
Configuration du composant Security de Symfony
1
#config/packages/security.yaml 
2
3
security:
4
    encoders:
5
        App\Entity\User:
6
            algorithm: auto
7
8
    providers:
9
        # used to reload user from session & other features (e.g. switch_user)
10
        app_user_provider:
11
            entity:
12
                class: App\Entity\User
13
                property: username
14
15
    firewalls:
16
        dev:
17
            pattern: ^/(_(profiler|wdt)|css|images|js)/
18
            security: false
19
        login:
20
            pattern:  ^/api/login
21
            stateless: true
22
            anonymous: true
23
            json_login:
24
                check_path: /api/login
25
                username_path: username
26
                password_path: password
27
                success_handler:          lexik_jwt_authentication.handler.authentication_success
28
                failure_handler:          lexik_jwt_authentication.handler.authentication_failure
29
        api:
30
            pattern:   ^/api
31
            stateless: true
32
            guard:
33
                authenticators:
34
                    - lexik_jwt_authentication.jwt_token_authenticator
35
36
    access_control:
37
        - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
38
        - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }
39
Fichier routes.yaml
1
#config/routes.yaml 
2
3
authentication_token:
4
  path: /api/login
5
  methods: ['POST']