Skip to content

Início de sessão sem palavra-passe WebAuthn

O Doggy implementa autenticação padrão WebAuthn baseada em web-auth/webauthn-symfony-bundle, com suporte para início de sessão com impressão digital, reconhecimento facial e chaves de segurança.

Visão geral

As credenciais WebAuthn são armazenadas em src/Entity/Security/WebauthnCredential.php (tabela webauthn_credentials), associadas a App\Entity\Organization\Employee (a entidade de utilizador).

O repositório de credenciais implementa PublicKeyCredentialSourceRepositoryInterface, com suporte para guardar e consultar credenciais WebAuthn.

Configuração

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']

Configuração do firewall de segurança

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'

Gestão de credenciais

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;   // ex.: "Chrome on Mac"

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

Fluxo de início de sessão

Registar um Passkey

  1. Após o início de sessão, o utilizador acede às definições de segurança (/user/webauthn/register/options)
  2. O browser invoca a API WebAuthn para criar a credencial
  3. O resultado é submetido em /user/webauthn/register/result
  4. A credencial de chave pública é armazenada na tabela webauthn_credentials

Início de sessão sem palavra-passe

  1. Introduzir o nome de utilizador e clicar em «Iniciar sessão com Passkey»
  2. POST para /login/webauthn/options para obter o desafio
  3. O browser invoca a API WebAuthn para assinar
  4. O resultado é submetido em /login/webauthn/result
  5. WebauthnSuccessHandler trata do início de sessão bem-sucedido (regista o dispositivo, atualiza a hora)

Processador de sucesso

App\Security\WebauthnSuccessHandler, após o início de sessão bem-sucedido:

  1. Atualiza a hora da última utilização da credencial
  2. Identifica automaticamente o nome do dispositivo (análise do User-Agent)
  3. Verifica se é o primeiro início de sessão e orienta a alteração da palavra-passe
  4. Suporta o fluxo de redefinição de palavra-passe

Repositório de credenciais WebAuthn

App\Repository\Security\WebauthnCredentialRepository implementa:

  • findOneByCredentialId(): consulta uma credencial
  • findAllForUserEntity(): obtém todas as credenciais do utilizador
  • saveCredentialSource(): cria/atualiza credenciais
  • parseUserAgent(): identificação do nome do dispositivo

Código aberto sob MIT | Copyright © 2026 Doggy