2009-10-21 25 views
13

Tôi sắp bắt đầu viết một ứng dụng Rails cho phép khách hàng có một tên miền phụ riêng biệt để truy cập vào ứng dụng của chúng tôi. Suy nghĩ từ quan điểm bảo mật dữ liệu, sẽ tốt hơn nếu quyền truy cập của từng khách hàng thực sự bị giới hạn trong cơ sở dữ liệu của họ, theo cách đó, nếu có lỗi trong mã sản xuất, họ chỉ có thể truy cập cơ sở dữ liệu của riêng họ chứ không phải của bất kỳ cơ sở dữ liệu nào khác khách hàng.Rails - Cơ sở dữ liệu riêng biệt cho mỗi tên miền phụ

Tôi biết mã đằng sau cách làm những gì tôi muốn, nhưng tôi đã tự hỏi nếu có một giải pháp đơn giản hơn mà tôi có thể bị thiếu. Làm thế nào bạn sẽ đi về việc bảo vệ dữ liệu khách hàng để trong trường hợp một lỗi hoặc hacker đe dọa, dữ liệu của họ sẽ ít có khả năng được tiếp xúc?

Trả lời

20

Dưới đây là một số mã tôi sử dụng cho vấn đề này rất:

application_controller.rb

before_filter :set_database 

helper_method :current_website 

# I use the entire domain, just change to find_by_subdomain and pass only the subdomain 
def current_website  
    @website ||= Website.find_by_domain(request.host) 
end 

def set_database 
    current_website.use_database 
end 

# Bonus - add view_path 
def set_paths 
    self.prepend_view_path current_website.view_path unless current_website.view_path.blank? 
end 

Website.rb

def use_database 
    ActiveRecord::Base.establish_connection(website_connection) 
end 

# Revert back to the shared database 
def revert_database 
    ActiveRecord::Base.establish_connection(default_connection) 
end 

private 

# Regular database.yml configuration hash 
def default_connection 
    @default_config ||= ActiveRecord::Base.connection.instance_variable_get("@config").dup 
end 

# Return regular connection hash but with database name changed 
# The database name is a attribute (column in the database) 
def website_connection 
    default_connection.dup.update(:database => database_name) 
end 

Hope this helps!

+0

+1 - Chắc chắn rất hữu ích. Bạn có thể cho tôi một ý tưởng về hiệu suất đạt được (nếu có chú ý) với cách tiếp cận này không? –

+0

Xin lỗi tôi không có điểm chuẩn về vấn đề này. Tôi chỉ có điều này làm việc trên một phiên bản beta tư nhân vào lúc này. – Kris

+0

Bất cứ ai có bất kỳ suy đoán về việc liệu điều này sẽ có một hit hiệu suất khủng khiếp hay không? Tôi muốn làm một cái gì đó tương tự cho một trang web sản xuất. – NotDan

0

Tắt đầu của bạn, bạn có thể chạy phiên bản máy chủ mới cho từng tên miền phụ bằng cách sử dụng môi trường khác nhau.

Nhưng điều đó sẽ không mở rộng rất tốt.

Tuy nhiên, số ít nhất google hits for multiple rails databases sẽ đưa ra một số đề xuất mới. Việc kết hợp thông tin trong các liên kết này cung cấp giải pháp hoàn toàn chưa được kiểm tra này cho một cá thể máy chủ duy nhất.

Bạn sẽ cần thêm mục nhập cơ sở dữ liệu cho mỗi tên miền phụ trong databases.yml của mình. Sau đó thêm before_filter vào bộ điều khiển ứng dụng của bạn

Cập nhật! Ví dụ tải lại cấu hình cơ sở dữ liệu động. Thật không may là không có cách nào tốt để làm cho đường dẫn cập nhật rộng mà không gây rối với nội bộ của máy chủ của bạn. Vì vậy, cấu hình cơ sở dữ liệu sẽ phải được tải lại trên mọi yêu cầu.

Ví dụ này giả định các mục cơ sở dữ liệu trong databases.yml được đặt tên theo tên miền phụ.

config/database.yml ứng dụng

login: &login 
    adapter: mysql 
    username: rails 
    password: IamAStrongPassword! 
    host: localhost 

production: 
    <<: *login 
    database: mysite_www 

subdomain1: 
    <<: *login 
    database: mysite_subdomain1 

subdomain2: 
    <<: *login 
    database: mysite_subdomain2 
... 

/controllers/application_controller.rb require 'ERB' before_filter: switch_db_connection

def switch_db_connection 
    subdomain = request.subdomains.first 
    ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(Rails.configuration.database_configuration_file)).result) 
    ActiveRecord::Base.establish_connection("mysite_#{subdomain}") 
end 

Như tôi đã nói nó hoàn toàn chưa được kiểm tra. Nhưng tôi không thấy trước bất kỳ vấn đề lớn nào. Nếu nó không làm việc hy vọng nó đặt bạn đi đúng hướng.

+1

Vấn đề với điều này là khi bạn thêm một tên miền phụ mới, bạn sẽ cần phải khởi động lại tất cả các trường hợp máy chủ. Nếu bạn đang thêm nhiều tên miền phụ cùng một lúc, điều này sẽ có nghĩa là một số thời gian chết. –

+1

Thực hiện ví dụ động trong một cá thể máy chủ duy nhất. Nó vẫn chưa được kiểm tra. – EmFi

0

Hóa ra tôi chỉ yêu cầu một số really similar question nhưng khá xa hơn một chút trong quá trình phát triển - Tôi đã bao gồm ba ý tưởng về cách sử dụng một cơ sở dữ liệu duy nhất trong đó.

+0

Cảm ơn bạn đã liên kết. Cung cấp cho tôi một vài ý tưởng, nhưng có vẻ như không có giải pháp thực sự tốt cho vấn đề này. –

4

Tôi tìm thấy một giải pháp khác nhau mà làm việc một chút dễ dàng hơn, nhưng làm cho các giả định bạn có một cơ sở dữ liệu cho mỗi Subdomain:

application_controller.rb

before_filter :subdomain_change_database 

def subdomain_change_database 
    if request.subdomain.present? && request.subdomain != "www" 
    # 'SOME_PREFIX_' + is optional, but would make DBs easier to delineate 
    ActiveRecord::Base.establish_connection(website_connection('SOME_PREFIX_' + request.subdomain)) 
    end 
end 

# Return regular connection hash but with database name changed 
# The database name is a attribute (column in the database) 
def website_connection(subdomain) 
    default_connection.dup.update(:database => subdomain) 
end 

# Regular database.yml configuration hash 
def default_connection 
    @default_config ||= ActiveRecord::Base.connection.instance_variable_get("@config").dup 
end 

Điều này sẽ chuyển sang cơ sở dữ liệu như mydb_subdomain. Đây là một tùy chọn cơ sở dữ liệu thay thế hoàn chỉnh, nhưng nó làm cho nó siêu dễ dàng để tung ra nhiều phiên bản.

Các vấn đề liên quan