37 lines
3.8 KiB
Markdown
37 lines
3.8 KiB
Markdown
# مصادقة SportPath — API v1
|
|
|
|
هذه الواجهات تأسيس أولي لمصادقة رقم الهاتف. لا تشغّل إرسال OTP قبل إعداد مزود حقيقي ومراجعة عقده على بيئة sandbox. لا يخرج الرمز أو المفاتيح في response أو logs.
|
|
|
|
## إعداد الخادم
|
|
|
|
ضع القيم في ملف البيئة الخاص خارج مجلد `public/`:
|
|
|
|
```dotenv
|
|
JWT_SIGNING_KEY=<random secret, at least 32 bytes>
|
|
JWT_ACCESS_TTL_SECONDS=900
|
|
JWT_REFRESH_TTL_DAYS=30
|
|
OTP_PROVIDER=generic_json
|
|
OTP_API_URL=https://provider.example/api/send
|
|
OTP_API_KEY=<server-only token>
|
|
OTP_SENDER_ID=<approved sender>
|
|
OTP_MESSAGE_TEMPLATE=رمز التحقق الخاص بك هو {code}
|
|
OTP_ENABLED=true
|
|
OTP_HASH_KEY=<independent random secret, at least 32 bytes>
|
|
```
|
|
|
|
المحول الحالي يرسل JSON بالشكل `{"to":"+...","sender":"...","message":"..."}` مع `Authorization: Bearer ...`، ويعد أي HTTP 2xx نجاحًا. هذا عقد عام مؤقت وليس افتراضًا عن أي مزود؛ عدّل `ConfiguredHttpOtpProvider` ليتوافق مع توثيق المزود الفعلي قبل تفعيل الإنتاج. يرفض endpoint العناوين غير HTTPS. في حال غياب الإعداد يبقى الطلب مغلقًا ويرجع 503.
|
|
|
|
## المسارات
|
|
|
|
- `POST /api/v1/auth/request-otp.php`: JSON `{ "phone_e164": "+962…", "purpose": "register|login", "device_uuid": "UUID" }`. يرد `challenge_id` ومدة الصلاحية. حد الإرسال الحالي 5 لكل رقم/ساعة، 20 لكل IP/ساعة، و10 لكل device/ساعة؛ المحاولات لكل تحدٍ 5 خلال 5 دقائق.
|
|
- `POST /api/v1/auth/verify-otp.php`: JSON `{ "challenge_id": "UUID", "code": "123456", "display_name": "…", "device_uuid": "UUID", "platform": "ios|android|web" }`. يستهلك التحدي مرة واحدة ويصدر JWT وrefresh token عشوائيًا. يجب حفظ refresh token في مخزن آمن على الجهاز، وعدم تسجيل أي token.
|
|
- `POST /api/v1/auth/refresh.php`: JSON `{ "refresh_token": "…" }`. تدوير الرمز يصدر refresh جديدًا؛ إعادة استخدام رمز سبق تدويره تبطل عائلة الجلسة.
|
|
- `POST /api/v1/auth/logout.php`: يتطلب `Authorization: Bearer <access-token>` ويبطل الجلسة الحالية.
|
|
- `/api/v1/admin/settings.php`: يتطلب bearer token ودور `owner` أو `content_manager`؛ GET للقراءة وPATCH للتعديل مع audit trail.
|
|
|
|
كل Access Token قصير العمر ويرتبط بجلسة حية في MySQL. الدور وحالة الحساب يعاد التحقق منهما من قاعدة البيانات لكل طلب محمي. لا تُقبل معرفات عتادية ثابتة؛ `device_uuid` معرّف تثبيت عشوائي. ترقية أول مالك تتم يدويًا على قاعدة الخادم بعد التحقق من رقم الهاتف، ولا توجد واجهة bootstrap عامة لمنح دور owner.
|
|
|
|
## ما لم يكتمل بعد
|
|
|
|
تطبيق Flutter مرتبط الآن بنقاط OTP والجلسات ويخزن الرموز في secure storage؛ مزامنة التمارين ترسل Bearer وتجدد الجلسة عند الحاجة. نقاط التتبع تقبل HMAC فقط إذا ضُبط `LEGACY_HMAC_ENABLED=true` صراحة لفترة ترحيل عميل قديم، وقيمته في المثال `false`. لم يُختبر اتصال MySQL الفعلي أو إرسال SMS؛ فحوص PHP/Dart حتى الآن ساكنة وتحليلية فقط. نفّذ migrations `001_phone_auth_and_sessions.sql` و`002_workout_idempotency.sql` و`003_training_content.sql` على staging بعد backup، وتحقق من rate limits والتدوير والإبطال مع مزود OTP في sandbox قبل الإنتاج.
|