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