【问题标题】:Rails: Every user has a own database userRails:每个用户都有自己的数据库用户
【发布时间】:2013-06-07 08:09:46
【问题描述】:

我的客户有一个现有的数据库,其中每个用户都有自己的数据库用户,他希望每个用户都使用自己的数据库用户登录到 rails 应用程序。

对于我的这个数据库模型,我使用ActiveRecord::Base::establish_connection 连接登录表单的用户名和密码。

现在我想在after_filter 中关闭此连接,以便其他用户无法从连接池中获取此连接。但这不起作用。

我想在我的控制器中使用这样的东西:

class Demo < ActiveRecord::Base
    before_filter :connect
    after_filter  :close_connection

    def action
       # do some stuff with the database
    end
end

我怎样才能通过ActiveRecord 实现这一点,或者有没有更好的解决方案来解决这个问题?或者是否有其他 ORM 映射器可以更好地解决这个问题?

我无法更改数据库或每个用户都有自己的数据库用户需要登录的事实,因为我的客户确实将此结构用于其他应用程序:(

这是一个 Postgres 数据库。和 Rails 3.2.13 (JRuby)。

【问题讨论】:

    标签: ruby-on-rails database activerecord


    【解决方案1】:

    首先,我从来没有开发过这种身份验证系统,但如果我必须这样做,我可能会选择Warden,这是一个集成为rack middleware 的身份验证系统。

    Warden 允许建立您自己的authentication strategies。所以我为你的情况做了一个例子,但请注意它不起作用。这只是为了清楚起见。

    这个想法是在机架中间件中使用给定的用户名/密码重新配置您的数据库池。机架中间件是请求中调用的第一个组件,所以我认为它应该避免性能问题。

    Warden::Strategies.add(:database_user) do
    
      def valid?
        ActiveRecord::Base.connected?
      end
    
      def authenticate!
        # Disconnects all connections in the pool, and clears the pool.
        ActiveRecord::Base.connection_pool.disconnect!
    
        # Reconfigure the pool with the new username/password
        config = Rails.application.config.database_configuration[Rails.env]
        config['username'] = params[:username]
        config['password'] = params[:password]
    
        # Establish connection with the new configuration
        ActiveRecord::Base.establish_connection(config)
    
        # Check if the connection works
        # It means that the username/password is correct
        if ActiveRecord::Base.connected?
          user = build_user(params[:username])
          success!(user)
        else
          fail!("Wrong username/password")
        end
    
      rescue # Errors thrown by Postgres
        fail!("Wrong username/password")
      end
    
      private
    
        def build_user(username)
          OpenStruct.new({username: username}) # Dynamic object
        end
    end
    

    然后在 Rails 配置文件中配置 Warden。

    Rails.configuration.middleware.use RailsWarden::Manager do |manager|
      manager.default_strategies :database_user
      manager.failure_app = LoginController
    end
    

    这只是一个原型,可让您深入了解如何解决您的问题。希望对你有所帮助。

    【讨论】:

    • 感谢您的提示,我回到办公室会试试这个。
    【解决方案2】:

    这不是在每个用户的每个请求上重置连接的好选择。最重要的是,它会丢失数据库缓存,因为您必须在每个请求中启动连接。

    最好尝试使用 Mongodb(如果可能),其中每条记录都属于一个用户,并且该用户的所有内容都将在该记录下。如果您正在尝试开发系统,则可以使用此解决方案。具有巨型数据库的现有系统可能认为这种解决方案是不可能的 :)

    【讨论】:

    • 使用 mongo 可以进行分片
    • 这也是我的想法,但是没有办法使用 mongodb :(
    猜你喜欢
    • 2013-09-27
    • 2013-01-09
    • 1970-01-01
    • 2021-03-04
    • 2013-11-25
    • 2019-12-02
    • 2017-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多