Skip to content

مزودو الرسائل القصيرة

يدعم FORGE إرسال رسائل SMS والتحقق من OTP عبر drivers مزودين متعددة. يُستخدم نظام SMS للتحقق من رقم الهاتف والمصادقة الثنائية والإشعارات التعاملية.

سمة SmsProvider

جميع drivers SMS تُنفّذ سمة SmsProvider:

rust
#[async_trait]
pub trait SmsProvider: Send + Sync {
    /// Send a plain text SMS message
    async fn send(&self, to: &str, message: &str) -> Result<(), SmsError>;

    /// Send a one-time password via the provider's verification service
    async fn send_otp(&self, to: &str, code: &str) -> Result<(), SmsError>;

    /// Verify an OTP code entered by the user
    async fn verify_otp(&self, to: &str, code: &str) -> Result<bool, SmsError>;
}

تكامل Slack (التطوير/الاختبار)

عندما يكون SMS_SLACK_ENABLED=true، يتم اعتراض جميع رسائل SMS وإرسالها إلى قناة Slack بدلاً من المزود الفعلي. هذا مفيد لـ:

  • التطوير: رؤية أكواد OTP بدون الحاجة لهاتف حقيقي
  • الاختبار: التحقق من محتوى SMS في مساحة عمل Slack
  • المراقبة: تتبع كل حركة SMS في قناة مخصصة
SMS_SLACK_ENABLED=true
┌─────────┐    ┌───────────────┐    ┌─────────────┐
│ التطبيق │───▶│ SlackSmsProxy │───▶│ قناة        │
│ يرسل    │    │ (يعترض)       │    │ Slack       │
│ SMS     │    └───────────────┘    └─────────────┘
└─────────┘

SMS_SLACK_ENABLED=false (افتراضي)
┌─────────┐    ┌─────────────────┐    ┌───────────────┐
│ التطبيق │───▶│ Twilio/Unifonic │───▶│ SMS حقيقية    │
│ يرسل    │    │ المزود          │    │ للهاتف        │
│ SMS     │    └─────────────────┘    └───────────────┘
└─────────┘

الإعدادات:

المتغيرالنوعالافتراضيمطلوبالوصف
SMS_SLACK_ENABLEDbooleanfalseلاإرسال SMS إلى Slack بدلاً من المزود
SMS_SLACK_WEBHOOK_URLstring-نعم*رابط Webhook الوارد لـ Slack
SMS_SLACK_CHANNELstring-لاتجاوز القناة اختيارياً

*مطلوب عندما يكون SMS_SLACK_ENABLED=true. سيفشل التطبيق عند البدء إذا كان مفقوداً.

الإعداد:

  1. أنشئ Incoming Webhook في مساحة عمل Slack
  2. عيّن متغيرات البيئة:
bash
SMS_SLACK_ENABLED=true
SMS_SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX
SMS_SLACK_CHANNEL=#sms-logs  # اختياري
  1. ستظهر رسائل SMS الآن في Slack:
*SMS Message*
:iphone: To: `+1234567890`
:envelope: Message:
رمز التحقق الخاص بك هو: 123456
:id: ID: `uuid-here`

تحذير

وكيل Slack لا يمكنه التحقق من OTPs - يجب إجراء التحقق عبر قاعدة البيانات الخاصة بك. هذا نفس سلوك driver الـ log.

الـ Drivers المتاحة

Slack (للتطوير)

إرسال رسائل SMS/OTP إلى قناة Slack بدلاً من الهواتف الحقيقية. مثالي للتطوير والاختبار بدون تكاليف SMS.

التثبيت:

bash
forge new --interactive
# اختر "Slack (development)" عند السؤال عن مزود SMS

أو عبر CLI:

bash
forge new myapp --sms slack

الإعدادات:

المتغيرالنوعمطلوبالوصف
SMS_DRIVERstringنعماضبطه على slack
SMS_SLACK_WEBHOOK_URLstringنعمرابط Webhook الوارد لـ Slack
SMS_SLACK_CHANNELstringلاتجاوز القناة اختيارياً

الإعداد:

  1. أنشئ Incoming Webhook في مساحة عمل Slack
  2. اضبط ملف .env:
bash
SMS_DRIVER=slack
SMS_SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX
SMS_SLACK_CHANNEL=#otp-codes  # اختياري
  1. ستظهر أكواد OTP في Slack:
*OTP Verification*
📱 *To:* `+1234567890`
🔑 *Code:* `123456`
🆔 *ID:* `uuid-here`

نصيحة

استخدم Slack للتطوير لتجنب تكاليف SMS ورؤية أكواد OTP فوراً في قناة فريقك.

تحذير

مزود Slack لا يمكنه التحقق من OTPs من جانب الخادم - يتم التحقق عبر قاعدة البيانات (مثل driver الـ Log).

Twilio

مزود SMS و OTP كامل الميزات باستخدام REST API و Verify service الخاصين بـ Twilio.

التثبيت:

bash
forge provider:add sms:twilio

الإعدادات:

الإعدادالنوعالوصف
twilio_account_sidstringTwilio Account SID
twilio_auth_tokenencryptedTwilio Auth Token
twilio_from_numberstringرقم هاتف المُرسل (بتنسيق E.164)
twilio_verify_sidstringTwilio Verify Service SID

نصيحة

twilio_verify_sid مطلوب لوظيفة OTP. أنشئ Verify Service في وحدة تحكم Twilio للحصول على هذه القيمة.

كيف يعمل OTP مع Twilio:

1. send_otp()  → يستدعي Twilio Verify API لإرسال الرمز
2. المستخدم يُدخل الرمز في تطبيقك
3. verify_otp() → يستدعي Twilio Verify API للتحقق من الرمز
4. يُرجع true/false

Unifonic

مزود SMS شائع في منطقة الشرق الأوسط وشمال أفريقيا.

التثبيت:

bash
forge provider:add sms:unifonic

الإعدادات:

الإعدادالنوعالوصف
unifonic_app_sidencryptedUnifonic Application SID
unifonic_sender_idstringمعرّف المُرسل (أبجدي رقمي أو رقم)

نصيحة

معرّفات المُرسل في Unifonic قد تتطلب تسجيلاً لدى هيئات الاتصالات المحلية حسب بلد الوجهة.

Vonage

مزود SMS عالمي (كان يُعرف سابقاً بـ Nexmo).

التثبيت:

bash
forge provider:add sms:vonage

الإعدادات:

الإعدادالنوعالوصف
vonage_api_keystringVonage API Key
vonage_api_secretencryptedVonage API Secret
vonage_fromstringمعرّف المُرسل أو الرقم

الاستخدام

إنشاء المزود

يُنشئ المصنع الـ driver الصحيح بناءً على إعداداتك:

rust
use crate::services::sms::SmsFactory;

let sms = SmsFactory::create(&settings).await?;

إرسال رسالة

rust
// إرسال SMS نصية عادية
sms.send("+1234567890", "تم شحن طلبك!").await?;

التحقق من OTP

rust
// Step 1: Send OTP to user's phone
sms.send_otp("+1234567890", "123456").await?;

// Step 2: User enters the code in your app

// Step 3: Verify the code
let is_valid = sms.verify_otp("+1234567890", "123456").await?;

if is_valid {
    // Phone number verified
} else {
    // Invalid code
}

تحذير

يجب أن تكون أرقام الهاتف بتنسيق E.164 (مثل +1234567890). الإرسال لأرقام بدون بادئة رمز البلد سيفشل مع معظم المزودين.

الإعدادات عبر الإدارة

جميع إعدادات SMS تُدار من خلال صفحة الإعدادات في الإدارة تحت مجموعة SMS. تُخزّن بيانات الاعتماد كإعدادات مُشفّرة وتُخفى في واجهة الإدارة.

الإعدادات > SMS
┌──────────────────────────────────────────────────┐
│  المزود:           [Twilio           ▼]          │
│  Account SID:      [ACxxxxxxxxxx       ]         │
│  Auth Token:       [••••••••••••••••   ]         │
│  رقم المُرسل:      [+15551234567       ]         │
│  Verify SID:       [VAxxxxxxxxxx       ]         │
└──────────────────────────────────────────────────┘

معالجة الأخطاء

جميع عمليات SMS تُرجع Result<(), SmsError> مع أنواع أخطاء منظمة:

rust
match sms.send("+1234567890", "مرحباً").await {
    Ok(()) => println!("تم إرسال الرسالة"),
    Err(SmsError::InvalidNumber) => println!("تنسيق رقم هاتف خاطئ"),
    Err(SmsError::ProviderError(msg)) => println!("خطأ المزود: {}", msg),
    Err(SmsError::RateLimited) => println!("طلبات كثيرة جداً"),
    Err(e) => println!("خطأ غير متوقع: {}", e),
}

Released under the MIT License.