ทำให้ Rails รองรับ CORS แบบง่ายๆ

Posted on June 16, 2015
By Karun Siritheerathamrong

Cross Origin Resource Sharing (CORS) คือกลไกที่ทำให้เว็บเซิร์ฟเวอร์สามารถอนุญาต หรือไม่อนุญาต การร้องขอทรัพยากรใดๆ ในหน้าเว็บ ที่ถูกเรียกมาจากโดเมนอื่น ที่ไม่ใช่โดเมนที่หน้าเว็บนั้นอยู่

ตัวอย่างการใช้งานทั่วไป

– หน้าเว็บใดๆ ในเว็บไซต์ xyz.com มีการเรียกไฟล์ฟอนต์ และรูปภาพจาก hahaha.com  แล้วเว็บ hahaha.com สามารถใช้ CORS เพื่อไม่อนุญาตให้เว็บอื่นๆ ที่ไม่ได้มาจากโดเมน hahaha.com สามารถเข้าถึงไฟล์ในเว็บได้

– เว็บ api.mydomain.com จะยอมรับเฉพาะคำร้องจากโดเมน mydomain.com และ myfrienddomain.com เท่านั้น ก็สามารถใช้ CORS เพื่ออนุญาตเฉพาะบางโดเมนได้

แม้การเปิดใช้งาน CORS จะช่วยลดปัญหาการเรียกใช้ทรัพยากรข้ามโดเมนหรือการเข้าถึงที่ไม่ได้รับอนุญาตได้ก็ตาม แต่การจะตั้งค่าให้เครื่องเซิร์ฟเวอร์รองรับการใช้งาน CORS ได้ก็ค่อนข้างยุ่งยากพอสมควร ดูจากมาตรฐานของ CORS จาก W3C

แม้กระทั่ง Rails ที่เป็น Web Framework ที่ทรงพลังก็ยังไม่ได้มีฟีเจอร์ที่สามารถเปิดใช้งาน CORS ได้มาให้ตั้งแต่แรก ครั้นจะทำการ implement ตามมาตรฐานของ W3C ก็ดูจะเป็นเรื่องที่ยุ่งยากเกินไป
จึงมีนักพัฒนาสร้างเจมชื่อ “rack-cors” ขึ้นมา ซึ่งเป็น Rack middleware  และทำหน้าที่จัดการการตั้งค่า รวมถึงการจัดการการรับ-ส่ง http header ให้เราเสร็จสรรพ

วิธีการใช้งานก็แสนง่ายดาย

1. เพิ่ม

[code language="ruby"]
gem 'rack-cors', require: 'rack/cors'
[/code]

เข้าไปใน Gemfile

2. สร้างไฟล์ config/initializers/rack_cors.rb และภายในมีเนื้อหาดังนี้

[code language="ruby"]
Rails.application.config.middleware.insert_before 0, "Rack::Cors", logger: (-> { Rails.logger }) do
  # From any origin
  allow do
    origins '*'
    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :head, :options]
  end
end
[/code]

origins ‘*’ หมายถึง ให้อนุญาตการร้องขอจากที่ใดๆ

resource ‘*’ หมายถึง อนุญาตให้เข้าถึงทรัพยากรใดๆ (และรวมถึง url ใดๆ ด้วย)

แค่นี้ก็สามารถใช้งาน CORS กับ Rails ได้แล้ว

ตัวอย่างอื่น

อนุญาตให้ localhost:3000 และ 127.0.0.1:3000 และเครื่องจาก 192.168.0.0/24 สามารถเข้าถึง /file/list_all และ /file/at/* ได้ พร้อมทั้งตั้งค่า Custom Headers ต่างๆ ตามต้องการ

แต่จากที่อื่นๆ จะอนุญาตให้เข้าถึงไฟล์ใดๆ จาก /public/ เท่านั้น

[code language="ruby"]
Rails.application.config.middleware.insert_before 0, "Rack::Cors", logger: (-> { Rails.logger }) do
allow do
    origins 'localhost:3000', '127.0.0.1:3000',
            /http:\/\/192\.168\.0\.\d{1,3}(:\d+)?/
            # regular expressions can be used here

    resource '/file/list_all/', :headers => 'x-domain-token'
    resource '/file/at/*',
        :methods => [:get, :post, :put, :delete, :options],
        :headers => 'x-domain-token',
        :expose  => ['Some-Custom-Response-Header'],
        :max_age => 600
        # headers to expose
  end

  allow do
    origins '*'
    resource '/public/*', :headers => :any, :methods => :get
  end
end
[/code]

ง่ายมากเลยใช่ไหมล่ะครับ 🙂