السماح بطلبات عبر الأصل فقط لحافلة الرسائل

أنا أحاول تطبيق أداة دردشة يمكن تضمينها في أي موقع ويب ولهذا قررت استخدام MessageBus للتواصل بين الأداة والواجهة الخلفية الخاصة بي في Rails. نظرًا لأنه يمكن تضمينها في أي مصدر، فقد احتجت إلى التعامل مع طلبات المصادر المتقاطعة.

ومع ذلك، أريد تمكين CORS فقط لطلبات MessageBus وليس لجميع مساراتي الأخرى. لقد رأيت بالفعل هذه المشكلة CORS configuration · Issue #135 · discourse/message_bus · GitHub

هذا ما فعلته في config/initializers/cors.rb.

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'
    resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options]
  end
end

إنها تعمل ولكن هذا يسمح بطلبات المصادر المتقاطعة لأي مسار وهو ليس ما أريده.

لقد حاولت أيضًا إنشاء برنامج وسيط خاص بي

# app/middleware/message_bus_cors_middleware.rb
class MessageBusCorsMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    # إذا كان الأمر يتعلق بـ message bus وطلب OPTIONS، فقم بإرجاع رؤوس CORS
    if env['PATH_INFO'].start_with?('/message-bus') && env['REQUEST_METHOD'] == 'OPTIONS'
      # تطبيق رؤوس CORS لطلبات /message-bus
      headers = {
        'Access-Control-Allow-Origin' => '*',
        'Access-Control-Allow-Methods' => 'GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD',
        'Access-Control-Allow-Headers' => 'Origin, X-Requested-With, Content-Type, Accept, Authorization, X-Visitor-Token',
        'Access-Control-Max-Age' => '86400'
      }
      [200, headers, []]
    else
      @app.call(env)
    end
  end
end

لكن لا يزال لدي مشاكل في المصادر المتقاطعة مع هذا البرنامج الوسيط.

أي فكرة أخرى؟

شيء آخر سيكون رائعًا هو تمكين المصادر المتقاطعة فقط لقنوات محددة. (في حالتي، قنوات MessageBus للدردشة). لقد استخدمت MessageBus في أجزاء أخرى من تطبيقي التي لا تقوم بطلبات المصادر المتقاطعة وأود الاحتفاظ بها على هذا النحو.

إعجابَين (2)

تمكنت من جعله يعمل باستخدام الطريقة الثانية (برنامج وسيط مخصص لتمكين CORS لطلبات Message Bus فقط). كانت المشكلة في access-control-allow-headers التي لم يتم تعيينها بالطريقة الصحيحة. كان الإصلاح هو ملء استجابة access-control-allow-headers برؤوس طلب Access-Control-Request-Headers.

إليك التنفيذ النهائي:

class MessageBusCorsMiddleware
  HTTP_ORIGIN = 'HTTP_ORIGIN'
  HTTP_X_ORIGIN = 'HTTP_X_ORIGIN'

  HTTP_ACCESS_CONTROL_REQUEST_METHOD = 'HTTP_ACCESS_CONTROL_REQUEST_METHOD'
  HTTP_ACCESS_CONTROL_REQUEST_HEADERS = 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS'
  OPTIONS = 'OPTIONS'
  REQUEST_METHOD = 'REQUEST_METHOD'
  PATH_INFO      = 'PATH_INFO'

  def initialize(app)
    @app = app
  end

  def call(env)
    # إذا كان طلب Message Bus وكان طلب OPTIONS، قم بإرجاع رؤوس CORS
    if env[PATH_INFO].start_with?('/message-bus') && env[REQUEST_METHOD] == OPTIONS && env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]
      origin = env['HTTP_ORIGIN']
      # تطبيق رؤوس CORS لطلبات /message-bus
      headers = {
        "access-control-allow-origin" => "*",
        "access-control-allow-methods" => "GET, POST, PUT, PATCH, DELETE, OPTIONS",
        "access-control-expose-headers" => "",
        "access-control-max-age" => "7200"
      }

      headers.merge!('access-control-allow-headers' => env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]) if env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]
      [200, headers, []]
    else
      @app.call(env)
    end
  end
end

كنت أواجه مشاكل في فهم دور رأس HTTP “Access-Control-Request-Headers” لذلك سألت ChatGPT:

يُستخدم رأس HTTP “Access-Control-Request-Headers” في سياق طلبات مشاركة الموارد عبر الأصول (CORS). CORS هي آلية تسمح لتطبيقات الويب بإجراء طلبات إلى مجال مختلف عن المجال الذي نشأت منه التطبيق.

عندما يقوم تطبيق ويب بإجراء طلب عبر الأصول، فإنه عادةً ما يرسل طلب “preflight” أولي إلى الخادم لتحديد ما إذا كان الطلب الفعلي مسموحًا به. يتضمن طلب preflight رأس “Access-Control-Request-Headers”، الذي يسرد الرؤوس الإضافية التي يرغب التطبيق في تضمينها في الطلب الفعلي.

على سبيل المثال، إذا أراد تطبيق ويب تضمين رؤوس مخصصة مثل “X-Auth-Token” أو “Authorization” في طلبه عبر الأصول، فسيحدد تلك الرؤوس في رأس “Access-Control-Request-Headers” في طلب preflight.

يمكن للخادم الذي يتلقى طلب preflight بعد ذلك فحص رأس “Access-Control-Request-Headers” لتحديد ما إذا كانت الرؤوس المطلوبة مسموحًا بها للطلب الفعلي. إذا وافق الخادم على الرؤوس المطلوبة، فإنه يستجيب برأس Access-Control-Allow-Headers المناسب في استجابة preflight، مما يسمح لتطبيق الويب بالمتابعة بالطلب الفعلي.

باختصار، “Access-Control-Request-Headers” هو رأس HTTP يُستخدم في طلبات CORS preflight لتحديد الرؤوس الإضافية التي يرغب تطبيق الويب في تضمينها في طلبه عبر الأصول.

أشارك هذا في حال كان شخص آخر يحاول تحقيق نفس الشيء. أنا أيضًا منفتح على الملاحظات خاصة فيما يتعلق بقضايا الأمان التي يمكن أن يفتحها هذا التنفيذ.

إعجاب واحد (1)

يمكنك إضافة رؤوس استجابة إضافية لكل المستندات:

في سبيل المثال في config/initializers/message_bus.rb:

MessageBus.extra_response_headers_lookup do |env|
  [
    ["Access-Control-Allow-Origin", "http://example.com:3000"],
  ]
end
إعجاب واحد (1)

لم أذكر ذلك، ولكن هذا هو أول شيء جربته ولم ينجح. ولكن ذلك كان قبل أن أعرف عن Access-Control-Allow-Headers. ربما سيعمل إذا أضفتها بهذه الطريقة.


MessageBus.extra_response_headers_lookup do |env|
 [
    ["Access-Control-Allow-Origin", "http://example.com:3000"],
    ["Access-Control-Allow-Headers", env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]]
  ]
end

سأحاول مرة أخرى بهذه الطريقة بدلاً من البرنامج الوسيط المخصص وسأقوم بتحديث هذا الموضوع.

لم يحالفني الحظ في ذلك أيضًا. في الوقت الحالي، احتفظت بالبرنامج الوسيط المخصص.