تسجيل الدخول بدون كلمة مرور عبر WebAuthn
ينفّذ Doggy مصادقة WebAuthn القياسية استنادًا إلى web-auth/webauthn-symfony-bundle، ويدعم تسجيل الدخول عبر بصمة الإصبع والتعرف على الوجه والمفاتيح الأمنية.
نظرة عامة
تُخزَّن بيانات اعتماد 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للحصول على التحدي (challenge) - يستدعي المتصفح واجهة WebAuthn API للتوقيع
- تُرسل النتيجة إلى
/login/webauthn/result - يعالج
WebauthnSuccessHandlerنجاح تسجيل الدخول (تسجيل الجهاز، تحديث الوقت)
معالج النجاح
يقوم App\Security\WebauthnSuccessHandler بعد نجاح تسجيل الدخول بـ:
- تحديث وقت آخر استخدام لبيانات الاعتماد
- التعرف التلقائي على اسم الجهاز (تحليل User-Agent)
- التحقق مما إذا كان هذا أول تسجيل دخول وتوجيه المستخدم لتغيير كلمة المرور
- دعم مسار إعادة تعيين كلمة المرور
مستودع بيانات اعتماد WebAuthn
ينفّذ App\Repository\Security\WebauthnCredentialRepository:
findOneByCredentialId(): البحث عن بيانات الاعتمادfindAllForUserEntity(): الحصول على جميع بيانات اعتماد المستخدمsaveCredentialSource(): إنشاء/تحديث بيانات الاعتمادparseUserAgent(): التعرف على اسم الجهاز