OOZOU
تواصلوا معنا
العودة إلى المدونة

المصادقة الثنائية بكلمات المرور لمرة واحدة (OTP) في Ruby on Rails باستخدام ROTP

تطبيق المصادقة الثنائية بكلمات مرور لمرة واحدة طريقة ممتازة لإضافة طبقة أمان إضافية لمستخدميكم.

8 يونيو 2020
5 دقائق للقراءة
المصادقة الثنائية بكلمات المرور لمرة واحدة (OTP) في Ruby on Rails باستخدام ROTP

ما هي المصادقة الثنائية بـ OTP؟

المصادقة الثنائية (2FA) تعني أن النظام يطلب خطوتين لتسجيل دخول المستخدم، مثل اسم المستخدم وكلمة المرور، ثم رمز يُرسل عبر البريد الإلكتروني أو رسالة SMS. أما المصادقة الثنائية بكلمة مرور لمرة واحدة (OTP 2FA) فهي أسهل على المستخدم، لأن الرمز يُولَّد على جهازه بفضل سرّ (secret) مشترك بين التطبيق والمستخدم. ولإعداد OTP، يمسح المستخدم أولًا رمز QR يحتوي على هذا السر، باستخدام تطبيق مثل Google Authenticator أو 1Password. وبعد الإعداد يستطيع جهاز المستخدم توليد رمز OTP يبقى صالحًا لفترة زمنية محددة، تتراوح عادة بين 15 و30 ثانية.

الإعداد

مع rtop gem يصبح إعداد المصادقة الثنائية بـ OTP بسيطًا جدًا. سأفترض أن لديكم نموذج مستخدم مع نظام مصادقة قائم، وغالبًا ما يكون Devise. لنثبّت rotp وrqrcode حتى نتمكن من توليد رموز QR تمسحونها من مدير كلمات المرور المفضل لديكم.

# Gemfile
gem 'rotp'
gem 'rqrcode'

إعداد ROTP

لإعداد ROTP نحتاج إلى إضافة عمود otp_secret وعمود last_otp_at (من نوع integer، لا date) إلى جدول User، وسنستخدمهما لتوليد رمز OTP التالي والتحقق منه.

bin/rails generate migration add_otp_secret_to_users otp_secret:string last_otp_at:integer
bin/rails db:migrate

توليد السر والتحقق من أول رمز OTP للمستخدم

نحتاج الآن إلى السماح للمستخدمين بإعداد OTP. أين تضعون ذلك في تطبيقكم قرار يعود إليكم، ومن منظور تجربة المستخدم هناك خياران:

  1. حماية OTP إلزامية
    • بعد التسجيل في التطبيق، أعيدوا توجيه المستخدم إلى صفحة إعداد OTP ليضبط سر OTP الخاص به
  2. حماية OTP اختيارية
    • اسمحوا للمستخدم بتفعيل حماية OTP أو إيقافها
      • بعد التفعيل، أعيدوا توجيهه إلى صفحة إعداد OTP ليضبط سر OTP الخاص به
      • بعد الإيقاف، احذفوا سر OTP

لإنشاء otp_secret نولّد سلسلة base32 باستخدام مكتبة ROTP، ثم نتحقق من أن المستخدم أعدّ تطبيق المصادقة لديه بشكل صحيح قبل حفظ السر، حتى لا نحرمه من الدخول إلى حسابه. سأنفذ كل ذلك داخل الـ controller لتسهيل العرض، لكنني أنصح بنقله إلى مكان آخر، مثل form objects أو service objects أو interactors.

# app/controllers/otp_secrets_controller.rb
class OtpSecretsController < ApplicationController
  def new
    @otp_secret = ROTP::Base32.random
    totp = ROTP::TOTP.new(
      @otp_secret, issuer: 'YourAppName'
    )
    @qr_code = RQRCode::QRCode
      .new(totp.provisioning_uri(current_user.email))
      .as_png(resize_exactly_to: 200)
      .to_data_url
  end

  def create
    @otp_secret = params[:otp_secret]
    totp = ROTP::TOTP.new(
      @otp_secret, issuer: 'YourAppName'
    )

    last_otp_at = totp.verify(
      params[:otp_attempt], drift_behind: 15
    )

    if last_otp_at
      current_user.update(
        otp_secret: @otp_secret, last_otp_at: last_otp_at
      )
      redirect_to(
        after_otp_configuration_path,
        notice: 'Successfully configured OTP protection for your account'
      )
    else
      flash.now[:alert] = 'The code you provided was invalid!'
      @qr_code = RQRCode::QRCode
        .new(totp.provisioning_uri(current_user.email))
        .as_png(resize_exactly_to: 200)
        .to_data_url
      render :new
    end
  end
end

الـ view

نحتاج الآن إلى إنشاء نموذج يعرض الـ action المسمى new أعلاه

# app/views/otp_secrets/new.html.erb
<%= form_tag otp_secrets_path, method: :post do %>
  <%= hidden_field_tag :otp_secret %>
  <%= image_tag @qr_code %>
  <%= text_field_tag :otp_attempt, label: "<strong>Verify (enter a one-time password)"</strong> %>
<% end %>

يُفترض أن يكون لديكم الآن شيء يشبه هذا هذا كل ما يلزم لإعداد المستخدم. بقي فقط أن نُلزم المستخدم بإدخال رمز OTP عند تسجيل الدخول

التحقق من رموز OTP عند تسجيل الدخول

إذا كنتم تُلزمون جميع المستخدمين بتأمين حساباتهم بـ OTP، فالأمر بسيط: أضيفوا حقل إدخال نصي إلى نموذج تسجيل الدخول وتحققوا منه. أما إذا كان OTP اختياريًا، فعليكم التحقق مما إذا كان مفعّلًا أثناء تسجيل الدخول، وتأجيل إتمام الدخول حتى يتحقق المستخدم من رمز OTP بنجاح. منطق التحقق من OTP بسيط للغاية. لقد نفذناه مرة من قبل، وكل ما نحتاجه تعديل بسيط ليشمل last_otp_attempt

last_otp_at = totp.verify(
  otp_attempt, after: user.last_otp_at, drift_behind: 15
)
if last_otp_at
  user.update(last_otp_at: last_otp_at)
else
	# Return an error to the user
end

أفكار إضافية

هذا كل ما في الأمر. يكفيكم هذا المقال للبدء، لكن هناك أمور أخرى تستحق التفكير:

  1. يجب تشفير otp_secret لحماية مستخدميكم في حال تسرّب قاعدة البيانات. أنا أستخدم attr_encrypted.
  2. عليكم إجراء بعض التحقق للتأكد من أن سر OTP لم يُعبث به. أفضّل استخدام ActiveSupport::MessageEncryptor لأتأكد من أن ما أرسلته إلى المستخدم هو نفسه ما يعود إليّ، ثم أفك ترميز السر وأعيد ترميزه للتأكد من أنه فعلًا سلسلة base32.
  3. إذا كنتم تستخدمون عملية تسجيل دخول من خطوتين، فتأكدوا من أن مستخدميكم:
    • لا يُعدّون مسجّلين فعليًا حتى تتحققوا من رمز OTP بنجاح.
    • أو أنشئوا before_action يتحقق من أنهم أدخلوا رمز OTP صحيحًا بعد آخر تسجيل دخول. والخيار الثاني أعلى تكلفة بكثير لأنه يُنفَّذ مع كل طلب.

Related Articles

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

تصميم البرمجيات عملية ممتعة لكنها معقدة، تتطلب الإبداع والتفكير المنطقي ومهارات حل المشكلات.

اقرأوا المزيد
مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

يتطور المشهد الرقمي بسرعة، وعلى الشركات أن تتكيّف لتواكب الطلب المتزايد على السرعة والكفاءة والمعالجة في الوقت الفعلي.

اقرأوا المزيد
مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

يتطور قطاع التجزئة بوتيرة غير مسبوقة بفضل الذكاء الاصطناعي (AI) والواقع المعزّز (AR) وتقنيات التحوّل الرقمي. فلم تعد المتاجر التقليدية مجرد أماكن لبيع المنتجات، بل أصبحت متاجر ذكية وتفاعلية.

اقرأوا المزيد

Have a Project in Mind?

Let's discuss how we can help bring your ideas to life with our expertise in web and mobile development.

ابدأوا المحادثةhello@oozou.com
OOZOU Logo

بانكوك · سنغافورة · هونغ كونغ

X
Facebook
Instagram
LinkedIn
OOZOU Co., Ltd.
548 One City Centre
Ploenchit Road
Bangkok 10330
Thailand
+66 2544 0000
hello@oozou.com

الخدمات

  • تطوير الويب
  • وكلاء الذكاء الاصطناعي والذكاء الاصطناعي التوليدي
  • تطوير تطبيقات الجوال
  • تحليلات البيانات وهندستها
  • تصميم تجربة المستخدم وواجهته (UX/UI) وتصميم المنتجات
  • التحوّل الرقمي

الشركة

  • من نحن
  • الوظائف
  • المدونة
  • دراسات الحالة
  • عروض حية
  • تعلّمت اليوم
  • تواصل معنا

المزيد

  • القطاعات
  • شبكة الشركاء
© 2026 OOZOU. جميع الحقوق محفوظة.
سياسة الخصوصيةمدونة قواعد السلوكسياسة مكافحة الرشوة والفساد