Rails - отдельная база данных на субдомен
Я собираюсь начать писать приложение Rails, которое позволит клиентам иметь отдельный субдомен для их доступа к нашему приложению. Разумеется, с точки зрения безопасности данных было бы неплохо, если бы каждый клиентский доступ был действительно ограничен их базой данных, таким образом, если в производственном коде есть ошибка, они смогут получить доступ к своей собственной базе данных, а не к любой другой клиентов.
Я знаю код, который касается того, как делать то, что я хочу, но мне было интересно, есть ли более простое решение, которое мне может не хватать. Как бы вы могли обеспечить безопасность данных клиента, чтобы в случае ошибки или угрозы хакером их данные были бы менее подвержены риску?
Ответы
Ответ 1
Вот какой код я использую для этой самой проблемы:
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
Надеюсь, это поможет!
Ответ 2
Я нашел другое решение, которое работает немного проще, но делает предположение, что у вас есть база данных для каждого поддомена:
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
Это переключится на базу данных, такую как mydb_subdomain. Это полная замена базы данных, но это делает ее очень легко развернуть несколько версий.
Ответ 3
В верхней части моей головы вы можете запустить новый экземпляр сервера для каждого поддомена с использованием другой среды.
Но это не будет очень хорошо масштабироваться.
Однако первые несколько хитов google для нескольких рельсовых баз данных добавляют некоторые новые предложения. Объединение информации в эти ссылки обеспечивает это полностью непроверенное решение для одного экземпляра сервера.
Вам нужно будет добавить запись базы данных для каждого поддомена в ваших базах данных .yml. Затем добавьте before_filter в контроллер приложения
Обновить! Пример перезагружает конфигурации базы данных динамически. К сожалению, нет хорошего способа сделать рельсы обновления широкими, не возившись с внутренними серверами. Таким образом, конфигурация базы данных должна быть перезагружена по каждому запросу.
В этом примере предполагается, что записи в базах данных databases.yml называются после поддоменов.
конфигурации /database.yml
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
...
приложение/контроллеры/application_controller.rb требуют "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
Как я уже сказал, он полностью непроверен. Но я не предвижу серьезных проблем. Если он не работает, надеюсь, он помещает вас на правильный путь.
Ответ 4
Оказывается, я просто задал действительно похожий вопрос, но еще немного продвинулся в разработке - я включил три идеи о том, как безопасно использовать один базы данных.