[#202] Authentification — Connexion utilisateur (JWT) (!5)

| Numéro du ticket | Titre du ticket |
|------------------|-----------------|
|      #202            |        Authentification — Connexion utilisateur (JWT)         |

## Description de la PR
[#202] Authentification — Connexion utilisateur (JWT)

## Modification du .env

## Check list

- [x] Pas de régression
- [ ] TU/TI/TF rédigée
- [x] TU/TI/TF OK
- [x] CHANGELOG modifié

Reviewed-on: https://gitea.malio.fr/MALIO-DEV/Ferme/pulls/5
Reviewed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit is contained in:
tristan
2026-01-20 20:06:29 +00:00
committed by Autin
parent 42fafc5d39
commit 8f5730c3f6
34 changed files with 932 additions and 48 deletions
+19 -7
View File
@@ -1,11 +1,23 @@
<?php
declare(strict_types=1);
use ApiPlatform\Symfony\Bundle\ApiPlatformBundle;
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle;
use Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle;
use Nelmio\CorsBundle\NelmioCorsBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Bundle\TwigBundle\TwigBundle;
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
FrameworkBundle::class => ['all' => true],
TwigBundle::class => ['all' => true],
SecurityBundle::class => ['all' => true],
DoctrineBundle::class => ['all' => true],
DoctrineMigrationsBundle::class => ['all' => true],
NelmioCorsBundle::class => ['all' => true],
LexikJWTAuthenticationBundle::class => ['all' => true],
ApiPlatformBundle::class => ['all' => true],
];
@@ -0,0 +1,20 @@
lexik_jwt_authentication:
secret_key: '%kernel.project_dir%/config/jwt/private.pem'
public_key: '%kernel.project_dir%/config/jwt/public.pem'
pass_phrase: '%env(JWT_PASSPHRASE)%'
token_ttl: 86400
token_extractors:
authorization_header:
enabled: true
prefix: Bearer
name: Authorization
cookie:
enabled: true
name: BEARER
set_cookies:
BEARER:
lifetime: 86400
path: /
samesite: lax
secure: '%env(bool:COOKIE_SECURE)%'
httpOnly: true
+1
View File
@@ -4,6 +4,7 @@ nelmio_cors:
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
allow_headers: ['Content-Type', 'Authorization']
allow_credentials: true
expose_headers: ['Link']
max_age: 3600
paths:
+4
View File
@@ -0,0 +1,4 @@
api_platform:
enable_docs: false
enable_swagger: false
enable_swagger_ui: false
+30 -6
View File
@@ -1,20 +1,43 @@
security:
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
App\Entity\User: 'auto'
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
users_in_memory: { memory: null }
app_user_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
# Ensure dev tools and static assets are always allowed
pattern: ^/(_profiler|_wdt|assets|build)/
security: false
main:
lazy: true
provider: users_in_memory
login:
pattern: ^/login_check
stateless: true
provider: app_user_provider
json_login:
check_path: /login_check
username_path: username
password_path: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ^/
stateless: true
provider: app_user_provider
jwt: ~
logout:
path: /logout
target: /login
enable_csrf: false
delete_cookies:
BEARER:
path: /
# Activate different ways to authenticate:
# https://symfony.com/doc/current/security.html#the-firewall
@@ -24,8 +47,9 @@ security:
# Note: Only the *first* matching rule is applied
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
- { path: ^/login_check, roles: PUBLIC_ACCESS }
- { path: ^/users, roles: PUBLIC_ACCESS, methods: [GET] }
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }
when@test:
security:
+96
View File
@@ -770,6 +770,9 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* property?: scalar|null|Param, // Default: null
* manager_name?: scalar|null|Param, // Default: null
* },
* lexik_jwt?: array{
* class?: scalar|null|Param, // Default: "Lexik\\Bundle\\JWTAuthenticationBundle\\Security\\User\\JWTUser"
* },
* }>,
* firewalls: array<string, array{ // Default: []
* pattern?: scalar|null|Param,
@@ -828,6 +831,10 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* provider?: scalar|null|Param,
* user?: scalar|null|Param, // Default: "REMOTE_USER"
* },
* jwt?: array{
* provider?: scalar|null|Param, // Default: null
* authenticator?: scalar|null|Param, // Default: "lexik_jwt_authentication.security.jwt_authenticator"
* },
* login_link?: array{
* check_route: scalar|null|Param, // Route that will validate the login link - e.g. "app_login_link_verify".
* check_post_only?: scalar|null|Param, // If true, only HTTP POST requests to "check_route" will be handled by the authenticator. // Default: false
@@ -1261,6 +1268,91 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* skip_same_as_origin?: bool|Param,
* }>,
* }
* @psalm-type LexikJwtAuthenticationConfig = array{
* public_key?: scalar|null|Param, // The key used to sign tokens (useless for HMAC). If not set, the key will be automatically computed from the secret key. // Default: null
* additional_public_keys?: list<scalar|null|Param>,
* secret_key?: scalar|null|Param, // The key used to sign tokens. It can be a raw secret (for HMAC), a raw RSA/ECDSA key or the path to a file itself being plaintext or PEM. // Default: null
* pass_phrase?: scalar|null|Param, // The key passphrase (useless for HMAC) // Default: ""
* token_ttl?: scalar|null|Param, // Default: 3600
* allow_no_expiration?: bool|Param, // Allow tokens without "exp" claim (i.e. indefinitely valid, no lifetime) to be considered valid. Caution: usage of this should be rare. // Default: false
* clock_skew?: scalar|null|Param, // Default: 0
* encoder?: array{
* service?: scalar|null|Param, // Default: "lexik_jwt_authentication.encoder.lcobucci"
* signature_algorithm?: scalar|null|Param, // Default: "RS256"
* },
* user_id_claim?: scalar|null|Param, // Default: "username"
* token_extractors?: array{
* authorization_header?: bool|array{
* enabled?: bool|Param, // Default: true
* prefix?: scalar|null|Param, // Default: "Bearer"
* name?: scalar|null|Param, // Default: "Authorization"
* },
* cookie?: bool|array{
* enabled?: bool|Param, // Default: false
* name?: scalar|null|Param, // Default: "BEARER"
* },
* query_parameter?: bool|array{
* enabled?: bool|Param, // Default: false
* name?: scalar|null|Param, // Default: "bearer"
* },
* split_cookie?: bool|array{
* enabled?: bool|Param, // Default: false
* cookies?: list<scalar|null|Param>,
* },
* },
* remove_token_from_body_when_cookies_used?: scalar|null|Param, // Default: true
* set_cookies?: array<string, array{ // Default: []
* lifetime?: scalar|null|Param, // The cookie lifetime. If null, the "token_ttl" option value will be used // Default: null
* samesite?: "none"|"lax"|"strict"|Param, // Default: "lax"
* path?: scalar|null|Param, // Default: "/"
* domain?: scalar|null|Param, // Default: null
* secure?: scalar|null|Param, // Default: true
* httpOnly?: scalar|null|Param, // Default: true
* partitioned?: scalar|null|Param, // Default: false
* split?: list<scalar|null|Param>,
* }>,
* api_platform?: bool|array{ // API Platform compatibility: add check_path in OpenAPI documentation.
* enabled?: bool|Param, // Default: false
* check_path?: scalar|null|Param, // The login check path to add in OpenAPI. // Default: null
* username_path?: scalar|null|Param, // The path to the username in the JSON body. // Default: null
* password_path?: scalar|null|Param, // The path to the password in the JSON body. // Default: null
* },
* access_token_issuance?: bool|array{
* enabled?: bool|Param, // Default: false
* signature?: array{
* algorithm: scalar|null|Param, // The algorithm use to sign the access tokens.
* key: scalar|null|Param, // The signature key. It shall be JWK encoded.
* },
* encryption?: bool|array{
* enabled?: bool|Param, // Default: false
* key_encryption_algorithm: scalar|null|Param, // The key encryption algorithm is used to encrypt the token.
* content_encryption_algorithm: scalar|null|Param, // The key encryption algorithm is used to encrypt the token.
* key: scalar|null|Param, // The encryption key. It shall be JWK encoded.
* },
* },
* access_token_verification?: bool|array{
* enabled?: bool|Param, // Default: false
* signature?: array{
* header_checkers?: list<scalar|null|Param>,
* claim_checkers?: list<scalar|null|Param>,
* mandatory_claims?: list<scalar|null|Param>,
* allowed_algorithms?: list<scalar|null|Param>,
* keyset: scalar|null|Param, // The signature keyset. It shall be JWKSet encoded.
* },
* encryption?: bool|array{
* enabled?: bool|Param, // Default: false
* continue_on_decryption_failure?: bool|Param, // If enable, non-encrypted tokens or tokens that failed during decryption or verification processes are accepted. // Default: false
* header_checkers?: list<scalar|null|Param>,
* allowed_key_encryption_algorithms?: list<scalar|null|Param>,
* allowed_content_encryption_algorithms?: list<scalar|null|Param>,
* keyset: scalar|null|Param, // The encryption keyset. It shall be JWKSet encoded.
* },
* },
* blocklist_token?: bool|array{
* enabled?: bool|Param, // Default: false
* cache?: scalar|null|Param, // Storage to track blocked tokens // Default: "cache.app"
* },
* }
* @psalm-type ApiPlatformConfig = array{
* title?: scalar|null|Param, // The title of the API. // Default: ""
* description?: scalar|null|Param, // The description of the API. // Default: ""
@@ -1526,6 +1618,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* doctrine?: DoctrineConfig,
* doctrine_migrations?: DoctrineMigrationsConfig,
* nelmio_cors?: NelmioCorsConfig,
* lexik_jwt_authentication?: LexikJwtAuthenticationConfig,
* api_platform?: ApiPlatformConfig,
* "when@dev"?: array{
* imports?: ImportsConfig,
@@ -1537,6 +1630,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* doctrine?: DoctrineConfig,
* doctrine_migrations?: DoctrineMigrationsConfig,
* nelmio_cors?: NelmioCorsConfig,
* lexik_jwt_authentication?: LexikJwtAuthenticationConfig,
* api_platform?: ApiPlatformConfig,
* },
* "when@prod"?: array{
@@ -1549,6 +1643,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* doctrine?: DoctrineConfig,
* doctrine_migrations?: DoctrineMigrationsConfig,
* nelmio_cors?: NelmioCorsConfig,
* lexik_jwt_authentication?: LexikJwtAuthenticationConfig,
* api_platform?: ApiPlatformConfig,
* },
* "when@test"?: array{
@@ -1561,6 +1656,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* doctrine?: DoctrineConfig,
* doctrine_migrations?: DoctrineMigrationsConfig,
* nelmio_cors?: NelmioCorsConfig,
* lexik_jwt_authentication?: LexikJwtAuthenticationConfig,
* api_platform?: ApiPlatformConfig,
* },
* ...<string, ExtensionType|array{ // extra keys must follow the when@%env% pattern or match an extension alias
+4
View File
@@ -1,3 +1,7 @@
_security_logout:
resource: security.route_loader.logout
type: service
api_login:
path: /login_check
methods: [POST]