Skip to content

WebAuthn 無密碼登入

Doggy 基於 web-auth/webauthn-symfony-bundle 實作 WebAuthn 標準認證,支援指紋、臉部辨識和安全金鑰登入。

概述

WebAuthn 憑證儲存在 src/Entity/Security/WebauthnCredential.php(表 webauthn_credentials),關聯至 App\Entity\Organization\Employee(使用者實體)。

憑證存放庫實作 PublicKeyCredentialSourceRepositoryInterface,支援儲存與查詢 WebAuthn 憑證。

設定

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

安全防火牆設定

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'

憑證管理

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;
}

登入流程

註冊 Passkey

  1. 使用者登入後進入安全設定(/user/webauthn/register/options
  2. 瀏覽器呼叫 WebAuthn API 建立憑證
  3. 結果提交至 /user/webauthn/register/result
  4. 公鑰憑證儲存至 webauthn_credentials

無密碼登入

  1. 輸入使用者名稱,點擊「Passkey 登入」
  2. POST 到 /login/webauthn/options 取得挑戰
  3. 瀏覽器呼叫 WebAuthn API 簽章
  4. 結果提交至 /login/webauthn/result
  5. WebauthnSuccessHandler 處理登入成功(記錄裝置、更新時間)

成功處理器

App\Security\WebauthnSuccessHandler 在登入成功後:

  1. 更新憑證最後使用時間
  2. 自動辨識裝置名稱(User-Agent 解析)
  3. 檢查是否為首次登入,引導密碼修改
  4. 支援密碼重設流程

WebAuthn 憑證存放庫

App\Repository\Security\WebauthnCredentialRepository 實作:

  • findOneByCredentialId():查詢憑證
  • findAllForUserEntity():取得使用者所有憑證
  • saveCredentialSource():建立/更新憑證
  • parseUserAgent():裝置名稱辨識

基於 MIT 協議開源 | Copyright © 2026 Doggy