แชร์เซสชัน (คุกกี้) ระหว่างโดเมนย่อยใน Rails?


93

ฉันมีการตั้งค่าแอปที่ผู้ใช้แต่ละคนเป็นของ บริษัท และ บริษัท นั้นมีโดเมนย่อย (ฉันใช้โดเมนย่อยสไตล์ basecamp) ปัญหาที่ฉันกำลังเผชิญคือทางรถไฟกำลังสร้างคุกกี้หลายตัว (อันหนึ่งสำหรับ lvh.me และอีกอันสำหรับ subdomain.lvh.me) ซึ่งทำให้แอปพลิเคชันของฉันหยุดพักค่อนข้างน้อย (เช่นข้อความแฟลชที่ไม่หยุดหย่อนแม้ว่าจะมีคำขอทั้งหมดเพียงครั้งเดียวก็ตาม ลงทะเบียนเข้า).

ฉันมีสิ่งนี้ในไฟล์ /cofig/initilizers/session_store.rb ของฉัน:

AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: :all

โดเมน:: ทั้งหมดนี้ดูเหมือนจะเป็นคำตอบมาตรฐานที่ฉันพบใน Google แต่ดูเหมือนจะไม่ได้ผลสำหรับฉัน ขอความช่วยเหลือใด ๆ !

คำตอบ:


76

เมื่อเปลี่ยนเป็น "โดเมนทั้งหมด" จะสร้างคุกกี้สำหรับโดเมนย่อยต่างๆทั้งหมดที่มีการเยี่ยมชมในระหว่างเซสชันนั้น (และทำให้แน่ใจว่ามีการส่งผ่านระหว่างคำขอ) หากไม่มีการส่งอาร์กิวเมนต์โดเมนหมายความว่าคุกกี้ใหม่ถูกสร้างขึ้นสำหรับทุกโดเมนที่แตกต่างกันที่เข้าชมในเซสชันเดียวกันและคุกกี้เก่าจะถูกทิ้ง สิ่งที่ฉันต้องการคือคุกกี้ตัวเดียวที่คงอยู่ตลอดเซสชันแม้ว่าโดเมนจะเปลี่ยนไป ดังนั้นการผ่านdomain: "lvh.me"แก้ไขปัญหาในการพัฒนา สิ่งนี้จะสร้างคุกกี้เดียวที่อยู่ระหว่างโดเมนย่อยต่างๆ

สำหรับใครก็ตามที่ต้องการคำอธิบายเพิ่มเติมนี่คือลิงค์ที่ดี: http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/


2
ขอบคุณเพื่อน .. ฉันประสบปัญหานี้กับหนึ่งในโครงการของฉัน .. ในที่สุดก็พบวิธีแก้ปัญหา ..
Shirjeel Alam

3
อย่าลืมใช้สิ่งเดียวกันconfig.secret_key_baseในทุกแอปพลิเคชันของคุณมิฉะนั้นจะไม่สามารถถอดรหัสคุกกี้ได้
Bruno Buccolo

6
ฉันไม่เห็นคำถามใด ๆ เกี่ยวกับเรื่องนี้สำหรับ Rails 4 คุณรู้หรือไม่ว่าสิ่งนี้มีการเปลี่ยนแปลงหรือไม่ ฉันไม่สามารถนำไปใช้กับโครงการของฉันได้ มันสร้างคุกกี้ขึ้นมาใหม่ ขอบคุณ.
Andy

จะเกิดอะไรขึ้นถ้าฉันต้องการใช้CacheStoreเพื่อจัดเก็บเซสชันใน memcached?
Amit Patel

2
ด้วย Rails4 ฉันพบว่าสิ่งนี้ใช้ได้กับโดเมนย่อยที่มีขีดกลางเท่านั้น แต่ไม่สามารถใช้กับขีดล่างได้:Appname::Application.config.session_store :cookie_store, key: '_appname_session', domain: :all, tld_length: 2
user1515295

68

http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/

"ส่วนที่คุณต้องระวังในที่นี้คือถ้าคุณตั้งค่า: domain =>: all like เป็นคำแนะนำในบางที่ก็จะใช้ไม่ได้เว้นแต่คุณจะใช้ localhost: ค่าเริ่มต้นทั้งหมดคือความยาว TLD เท่ากับ 1 ซึ่งหมายความว่าหากคุณทดสอบด้วย Pow (myapp.dev) มันจะใช้ไม่ได้เช่นกันเพราะนั่นคือ TLD ของความยาว 2 "

กล่าวอีกนัยหนึ่งคุณต้องการ:

 App.config.session_store ... , :domain => :all, :tld_length => 2

นอกจากนี้คุณควรล้างคุกกี้ของคุณด้วย


1
นี่เป็นคำตอบที่ดีที่สุดเพราะการเปลี่ยนแปลงเดียวใช้ได้กับทุกสภาพแวดล้อม (app.com และ app.dev) ไม่จำเป็นต้องใช้ตัวกลางที่กำหนดเอง ยังเป็นจุดที่ดีในการล้างคุกกี้!
Turadg

1
คุณกำลังพลาด, :tld_length => 2
montrealmike

1
อย่าลืมใช้สิ่งเดียวกันconfig.secret_key_baseในทุกแอปพลิเคชันของคุณมิฉะนั้นจะไม่สามารถถอดรหัสคุกกี้ได้
Bruno Buccolo

4
:domain => :allจะไม่ทำงานในรางที่ 4 domain => 'lvh.me', tld_length = 2ลอง มันได้ผลสำหรับฉัน
Minh Triet

1
ด้วย Rails 4.2 ฉันได้ผลลัพธ์ที่ดีdomain: :all, tld_length: 2ในขณะที่ใช้lvh.meโดเมน
zwippie

24

ฉันกำลังมองหาวิธีแก้ปัญหานี้โดยไม่ต้องระบุชื่อโดเมนอย่างชัดเจนดังนั้นฉันจึงสามารถข้ามไปมาระหว่าง localhost, lvh.me และโดเมนใดก็ได้ที่ฉันจะใช้ในการผลิตโดยไม่ต้องแก้ไขไฟล์ session_store.rb ต่อไป อย่างไรก็ตามการตั้งค่า "โดเมน: ทั้งหมด" ดูเหมือนจะไม่ได้ผลสำหรับฉัน

ในที่สุดฉันพบว่าฉันจำเป็นต้องระบุ tld_length (ความยาวโดเมนระดับบนสุด) ในนิพจน์นั้น tld_length เริ่มต้นคือ 1 ในขณะที่ example.lvh.me มี tld_length เป็น 2 และ 127.0.0.1.xip.io มี tld_length เท่ากับ 5 เป็นต้น ดังนั้นสิ่งที่ฉันมีในไฟล์ session_store.rb สำหรับโดเมนย่อยบน lvh.me ในการพัฒนาและสิ่งอื่น ๆ ในการผลิตมีดังต่อไปนี้

MyApp::Application.config.session_store :cookie_store, key: '_MyApp_session', domain: :all, tld_length: 2

หวังว่านี่จะช่วยใครสักคนเพราะฉันใช้เวลานานในการค้นหาคำตอบนี้!


19

ด้วยเหตุผลบางอย่างการแทนที่:allด้วยโดเมนไม่ได้ผล (ราง 3.2.11) สำหรับฉัน ต้องใช้มิดเดิลแวร์ที่กำหนดเองส่วนหนึ่งในการแก้ไข สรุปวิธีแก้ปัญหานั้นอยู่ด้านล่าง

tl; dr:คุณต้องเขียน Rack Middleware ที่กำหนดเอง คุณต้องเพิ่มลงในconifg/environments/[production|development].rbไฟล์. นี่คือบน Rails 3.2.11

โดยปกติเซสชันคุกกี้จะถูกเก็บไว้สำหรับโดเมนระดับบนสุดของคุณเท่านั้น

หากคุณดูในChrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com}คุณจะเห็นว่าจะมีรายการแยกต่างหากสำหรับsub1.yourdomain.comและothersub.yourdomain.comและyourdomain.com

ความท้าทายคือการใช้ไฟล์เก็บเซสชันเดียวกันในโดเมนย่อยทั้งหมด

ขั้นตอนที่ 1: เพิ่มคลาสมิดเดิลแวร์ที่กำหนดเอง

นี่คือที่มาของRack Middlewareทรัพยากรชั้นวางและรางที่เกี่ยวข้อง:

นี่คือคลาสแบบกำหนดเองที่คุณควรเพิ่มในสิ่งlib นี้เขียนโดย@Naderและคุณทุกคนควรขอบคุณเขา

# Custom Domain Cookie
#
# Set the cookie domain to the custom domain if it's present
class CustomDomainCookie
  def initialize(app, default_domain)
    @app = app
    @default_domain = default_domain
  end

  def call(env)
    host = env["HTTP_HOST"].split(':').first
    env["rack.session.options"][:domain] = custom_domain?(host) ? ".#{host}" : "#{@default_domain}"
    @app.call(env)
  end

  def custom_domain?(host)
    host !~ /#{@default_domain.sub(/^\./, '')}/i
  end
end

โดยพื้นฐานแล้วสิ่งนี้คือการแมปข้อมูลเซสชันคุกกี้ทั้งหมดของคุณกลับไปยังไฟล์คุกกี้เดียวกันทั้งหมดที่มีค่าเท่ากับโดเมนรากของคุณ

ขั้นตอนที่ 2: เพิ่มในการกำหนดค่าราง

ตอนนี้คุณมีคลาสที่กำหนดเองใน lib แล้วตรวจสอบให้แน่ใจว่าได้โหลดอัตโนมัติแล้ว หากนั่นไม่มีความหมายสำหรับคุณโปรดดูที่นี่: Rails 3 autoload

สิ่งแรกคือตรวจสอบให้แน่ใจว่าคุณใช้งานที่เก็บคุกกี้ทั้งระบบ ในconfig/application.rbเราบอกทางรถไฟที่จะใช้เก็บคุกกี้

# We use a cookie_store for session data
config.session_store :cookie_store,
                     :key => '_yourappsession',
                     :domain => :all

เหตุผลที่กล่าวถึงที่นี่เป็นเพราะ:domain => :allเส้น มีคนอื่น ๆ ที่มีข้อเสนอแนะในการระบุเป็นแทน:domain => ".yourdomain.com" :domain => :allด้วยเหตุผลบางประการสิ่งนี้ไม่ได้ผลสำหรับฉันและฉันต้องการคลาส Middleware ที่กำหนดเองตามที่อธิบายไว้ข้างต้น

จากนั้นในการconfig/environments/production.rbเพิ่มของคุณ:

config.middleware.use "CustomDomainCookie", ".yourdomain.com"

โปรดทราบว่าจุดก่อนหน้าเป็นสิ่งที่จำเป็น ดู " คุกกี้โดเมนย่อยที่ส่งในคำขอโดเมนหลักหรือไม่ " สำหรับสาเหตุ

จากนั้นในการconfig/environments/development.rbเพิ่มของคุณ:

config.middleware.use "CustomDomainCookie", ".lvh.me"

แผนที่เคล็ดลับ lvh.me เข้าสู่ localhost มันเจ๋งมาก. ดูRailscast เกี่ยวกับโดเมนย่อยและหมายเหตุนี้สำหรับข้อมูลเพิ่มเติม

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


มีวิธีทำให้สิ่งนี้ใช้ได้กับโดเมนระดับบนสุดหลายโดเมนหรือไม่ ฉันมีผลิตภัณฑ์ที่ทำงานในประเทศต่างๆ ที่นี่เราสมมติว่าโดเมนเริ่มต้นคือ yourdomain.com แต่จะเป็นอย่างไรหากควรใช้กับ. be .sv .fr .com.br .com.ar และอื่น ๆ ขอบคุณ.
Marc Lainez

ฉันไม่สามารถทำงานนี้ได้ ฉันกำลังพัฒนาในราง 4 และดูเหมือนว่า rials จะละเว้นโค้ดทั้งหมดข้างต้นเบา ๆ ไม่ต้องการแชร์เซสชันข้ามโดเมนย่อย
Ole Henrik Skogstrøm

@ OleHenrikSkogstrømอย่าลืมใช้สิ่งเดียวกันconfig.secret_key_baseในทุกแอปพลิเคชันของคุณมิฉะนั้นจะไม่สามารถถอดรหัสคุกกี้ได้
Bruno Buccolo

17

ฉันเจอสิ่งนี้ในขณะที่กำลังมองหาวิธีที่ง่ายที่สุดในการตั้งค่าคุกกี้ให้เป็นโดเมนราก ดูเหมือนว่ามีข้อมูลที่ผิดเกี่ยวกับ:allตัวเลือกเมื่อส่งผ่านเป็นตัวเลือกโดเมน สำหรับโดเมนส่วนใหญ่จะใช้งานได้จริงตามที่คาดไว้โดยตั้งค่าคุกกี้เป็นโดเมนราก (เช่น.example.comสำหรับtest.example.com) ฉันคิดว่าคนส่วนใหญ่ประสบปัญหาเนื่องจากใช้โดเมนlvh.meเพื่อทดสอบ regex DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/ที่ใช้โดยทางรถไฟที่จะหาโดเมนระดับบนสุดถูกกำหนดให้เป็น หากคุณทราบส่วนสุดท้ายที่คุณจะเห็นว่ารางตีความlvh.meเป็น TLD com.auจะคล้ายกัน หากกรณีการใช้งานของคุณจำเป็นต้องlvh.meใช้งาน:allตัวเลือกจะทำงานไม่ถูกต้องอย่างไรก็ตามดูเหมือนว่าจะเป็นตัวเลือกที่ง่ายและดีที่สุดสำหรับโดเมนส่วนใหญ่

TL; DR คำตอบที่ถูกต้องที่นี่สมมติว่าคุณจะไม่ได้รับการพัฒนาบนโดเมนอักษร 3 (หรือโดเมนใด ๆ ที่สับสน regex ด้านบน) :allคือการใช้งาน


ขอบคุณในที่สุดสิ่งนี้ก็ช่วยให้ฉันเข้าใจว่าทำไมคำตอบมากมายจึงแนะนำ tld_length เป็น 2 แต่ทำไมฉันไม่ต้องการ!
ซุปด็อก

คำตอบนี้จะต้องสูงขึ้น ขอบคุณครับ
luca.busin

"lvh.me เป็น TLD คล้ายกับ com.au" BTW Rails ควรแปลความหมายเช่นเดียวกับโดเมนประเทศ (มอนเตเนโกร)
mahemoff

8

Rails 4.x (ควรใช้ได้กับ Rails 5/6 เวอร์ชัน)

วิธีรับ lvh.me:3000 และโดเมนย่อยใน localhost (Rails)

การพัฒนา: ผมได้ร่วมกันคุกกี้เพื่อเพิ่ม.lvh.meเข้าไปsession_store.rb,

มันจะถูกใช้ร่วมกันระหว่างโดเมนย่อยใน localhost admin.lvh.me:3000, lvh.me:3000และอื่น ๆ ...

#config/initializers/session_store.rb

domain = Rails.env.production? ? ".domain_name.com" : ".lvh.me"

Rails.application.config.session_store :cookie_store, 
                      key: '_app_name_session', domain: domain

4

คุณลอง

AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: 'lvh.me'  

)

โดยทั่วไปเรากำลังบอกว่ามีคุกกี้เดียวสำหรับโดเมนฐานและเพียงแค่เพิกเฉยต่อโดเมนย่อย ... แม้ว่าวิธีนี้จะมีข้อบกพร่องอยู่บ้าง ...


2

รางรองรับ 5

หากคุณต้องการใช้งานกับโดเมนใดก็ได้:

Rails.application.config.session_store :cookie_store, key: '_my_app_session', domain: :all, tld_length: 2

ในการกำหนดค่าตามสภาพแวดล้อมคุณสามารถใช้สิ่งต่อไปนี้:

Rails.application.config.session_store :cookie_store, key: '_my_app_session', domain: {
  production: '.example.com',
  development: '.example.dev'
}.fetch(Rails.env.to_sym, :all)

อ้างอิง: https://github.com/plataformatec/devise/wiki/How-To:-Use-subdomains


0

หากคุณใช้ Redis สำหรับร้านค้าเซสชัน

if Rails.env.development?
    Rails.application.config.session_store :redis_store, {
       servers: [
        { host: 'localhost', port: 6379},
      ],
      key: '_app_session',
      expire_after: 1.day,
      domain: :all
    }

else
    Rails.application.config.session_store :redis_store, {
       servers: [
        { host: HOST_URL, port: PORT},
      ],
      key: '_app_session',
      expire_after: 1.day,
      domain: '.domain.com',
      tld_length: 2
    }
    
end 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.