2009-10-21 22 views
13

Estoy a punto de comenzar a escribir una aplicación de Rails que permitirá a los clientes tener un subdominio separado para acceder a nuestra aplicación. Pensando desde el punto de vista de la seguridad de datos, sería bueno que el acceso de cada cliente estuviera realmente limitado a su base de datos, de ese modo, si hay un error en el código de producción, solo podrían acceder a su propia base de datos y no a otra. clientela.Rieles: base de datos separada por subdominio

Sé el código detrás de cómo hacer lo que quiero, pero me preguntaba si había una solución más simple que me podría estar perdiendo. ¿Cómo protegerías los datos del cliente para que, en caso de una amenaza de error o pirata informático, tuvieran menos posibilidades de ser expuestos?

Respuesta

20

Aquí hay un código que utilizo para este mismo problema:

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 

Espero que esto ayude!

+0

+1 - Definitivamente muy útil. ¿Me puede dar una idea del rendimiento alcanzado (si es que se nota) con este enfoque? –

+0

Lo siento, no tengo un punto de referencia con respecto a esto. Solo tengo esto trabajando en una versión beta privada en este momento. – Kris

+0

¿Alguien tiene alguna especulación sobre si esto tendrá un rendimiento terrible o no? Me gustaría hacer algo similar para un sitio de producción. – NotDan

0

En la parte superior de mi cabeza podría ejecutar una nueva instancia de servidor para cada subdominio utilizando un entorno diferente.

Pero eso no se escalará muy bien.

Sin embargo, las primeras google hits for multiple rails databases arrojan algunas sugerencias nuevas. Al juntar la información en esos enlaces se proporciona esta solución totalmente no probada para una sola instancia de servidor.

Deberá agregar una entrada de base de datos para cada subdominio en sus databases.yml. A continuación, agregue un before_filter a su controlador de aplicación

¡Actualización! Ejemplo recarga las configuraciones de la base de datos dinámicamente. Lamentablemente, no hay una buena manera de hacer que la actualización se desplace a gran velocidad sin interferir con el funcionamiento interno de su servidor. Por lo tanto, la configuración de la base de datos tendrá que volver a cargarse en cada solicitud.

Este ejemplo supone que las entradas de la base de datos en databases.yml llevan el nombre de los subdominios.

config/database.yml aplicación

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 
... 

/controladores/application_controller.rb requieren '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 

Como ya he dicho que es completamente sin probar. Pero no preveo ningún problema importante. Si no funciona con suerte, te pone en el camino correcto.

+1

El problema con esto es que cuando agrega un nuevo subdominio va a necesitar reiniciar todas las instancias del servidor. Si agrega muchos subdominios a la vez, esto significará un tiempo de inactividad. –

+1

Hizo el ejemplo dinámico en una instancia de servidor único. Sin embargo, aún no se ha probado. – EmFi

0

Resulta que acabo de pedir un really similar question, pero un poco más adelante en el desarrollo: he incluido tres ideas sobre cómo utilizar de forma segura una base de datos única allí.

+0

Gracias por el enlace. Me da algunas ideas, pero parece que todavía no hay una solución realmente buena para este problema. –

4

he encontrado una solución diferente que funciona un poco más fácil, pero hace la suposición de que tiene una base de datos para cada subdominio:

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 

Esto cambiará a una base de datos como mydb_subdomain. Esta es una opción de base de datos de reemplazo completa, pero hace que sea muy fácil implementar múltiples versiones.

Cuestiones relacionadas