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
- 用户登录后进入安全设置(
/user/webauthn/register/options) - 浏览器调用 WebAuthn API 创建凭证
- 结果提交到
/user/webauthn/register/result - 公钥凭证存储到
webauthn_credentials表
无密码登录
- 输入用户名,点击「Passkey 登录」
- POST 到
/login/webauthn/options获取挑战 - 浏览器调用 WebAuthn API 签名
- 结果提交到
/login/webauthn/result WebauthnSuccessHandler处理登录成功(记录设备、更新时间)
成功处理器
App\Security\WebauthnSuccessHandler 在登录成功后:
- 更新凭证最后使用时间
- 自动识别设备名称(User-Agent 解析)
- 检查是否首次登录,引导密码修改
- 支持密码重置流程
WebAuthn 凭证仓库
App\Repository\Security\WebauthnCredentialRepository 实现:
findOneByCredentialId():查找凭证findAllForUserEntity():获取用户所有凭证saveCredentialSource():创建/更新凭证parseUserAgent():设备名称识别