Skip to content

Connexion sans mot de passe WebAuthn

Doggy implémente l'authentification standard WebAuthn via web-auth/webauthn-symfony-bundle, avec prise en charge de la connexion par empreinte digitale, reconnaissance faciale et clé de sécurité.

Aperçu

Les informations d'identification WebAuthn sont stockées dans src/Entity/Security/WebauthnCredential.php (table webauthn_credentials), associées à App\Entity\Organization\Employee (l'entité utilisateur).

Le dépôt de certificats implémente PublicKeyCredentialSourceRepositoryInterface, avec prise en charge de l'enregistrement et de la consultation des informations d'identification WebAuthn.

Configuration

yaml
# config/packages/webauthn.yaml
webauthn:
  credential_repository: 'App\Repository\Security\WebauthnCredentialRepository'
  user_repository: 'App\Repository\Organization\EmployeeRepository'
  creation_profiles:
    default:
      rp:
        name: '%env(RELYING_PARTY_NAME)%'
        id: '%env(RELYING_PARTY_ID)%'
      public_key_credential_parameters:
        - -7    # ES256
        - -257  # RS256
      authenticator_selection_criteria:
        resident_key: required
        user_verification: required
  request_profiles:
    default:
      rp_id: '%env(RELYING_PARTY_ID)%'
      user_verification: required
  allowed_origins: ['http://localhost:8000']

Configuration du pare-feu de sécurité

yaml
# config/packages/security.yaml
security:
  firewalls:
    main:
      custom_authenticator: App\Security\AppCustomAuthenticator
      webauthn:
        success_handler: App\Security\WebauthnSuccessHandler
        authentication:
          enabled: true
          routes:
            options_path: '/login/webauthn/options'
            result_path: '/login/webauthn/result'

Gestion des informations d'identification

php
// src/Entity/Security/WebauthnCredential.php
class WebauthnCredential
{
    private string $publicKeyCredentialId;
    private string $type;          // 'public-key'
    private array $transports;     // ['usb', 'nfc', 'internal']
    private string $attestationType;
    private string $credentialPublicKey;
    private string $userHandle;    // Employee ID
    private int $counter;
    private ?string $deviceName;   // 如 "Chrome on Mac"

    #[ORM\ManyToOne(targetEntity: Employee::class, inversedBy: 'passkeys')]
    private ?Employee $employee = null;
}

Flux de connexion

Enregistrer un Passkey

  1. Après connexion, l'utilisateur accède aux paramètres de sécurité (/user/webauthn/register/options)
  2. Le navigateur appelle l'API WebAuthn pour créer les informations d'identification
  3. Le résultat est soumis à /user/webauthn/register/result
  4. Les informations d'identification à clé publique sont stockées dans la table webauthn_credentials

Connexion sans mot de passe

  1. Saisissez le nom d'utilisateur et cliquez sur « Connexion Passkey »
  2. POST vers /login/webauthn/options pour obtenir le défi (challenge)
  3. Le navigateur appelle l'API WebAuthn pour signer
  4. Le résultat est soumis à /login/webauthn/result
  5. WebauthnSuccessHandler traite la connexion réussie (enregistrement de l'appareil, mise à jour de l'horodatage)

Gestionnaire de succès

App\Security\WebauthnSuccessHandler, après une connexion réussie :

  1. Met à jour la date de dernière utilisation des informations d'identification
  2. Identifie automatiquement le nom de l'appareil (analyse du User-Agent)
  3. Vérifie s'il s'agit de la première connexion et guide vers la modification du mot de passe
  4. Prend en charge le flux de réinitialisation du mot de passe

Dépôt des informations d'identification WebAuthn

Implémentation de App\Repository\Security\WebauthnCredentialRepository :

  • findOneByCredentialId() : recherche les informations d'identification
  • findAllForUserEntity() : récupère toutes les informations d'identification d'un utilisateur
  • saveCredentialSource() : création/mise à jour des informations d'identification
  • parseUserAgent() : identification du nom de l'appareil

Open source sous licence MIT | Copyright © 2026 Doggy