Question

En utilisant les informations et exemples présentés dans les deux sections, sécurisez votre API (utilisant API Platform) et votre documentation d'API grâce au mécanisme de JWT et au bundle Lexic Authentication JWT.

Testez ensuite votre authentification et sécurité en utilisant Postman et la documentation d'API.

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
}
113
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 ###
10
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']
Fichier api_platform.yaml
1
#config/packages/api_platform.yaml 
2
3
api_platform:
4
    title: 'Symfony REST API'
5
    description: 'À Symfony API to manage a simple blog app.'
6
    version: '1.0.0'
7
    mapping:
8
        paths: ['%kernel.project_dir%/src/Entity']
9
    patch_formats:
10
        json: ['application/merge-patch+json']
11
    swagger:
12
        versions: [3]
13
        api_keys:
14
            apiKey:
15
                name: Authorization
16
                type: header