我在 Rails 4 + Devise 3.2 应用程序中遇到了一个奇怪的问题,它允许用户通过 AJAX POST 将密码更改为以下操作,源自 Devise wiki Allow users to edit their password . 好像是在用户修改密码后,经过一次或多次请求后,会被强制注销,重新登录后还会继续被强制注销。
# POST /update_my_password
def update_my_password
@user = User.find(current_user.id)
authorize! :update, @user ## CanCan check here as well
if @user.valid_password?(params[:old_password])
@user.password = params[:new_password]
@user.password_confirmation = params[:new_password_conf]
if @user.save
sign_in @user, :bypass => true
head :no_content
return
end
else
render :json => { "error_code" => "Incorrect password" }, :status => 401
return
end
render :json => { :errors => @user.errors }, :status => 422
end
此操作实际上在开发中运行良好,但是当我运行多线程、多工作器 Puma 实例时,它在生产中失败。似乎发生的是,用户将保持登录状态,直到他们的一个请求到达不同的线程,然后他们以
Unauthorized
的身份注销。具有 401 响应状态。如果我使用单个线程和单个工作人员运行 Puma,则不会出现此问题。我似乎允许用户使用多个线程再次保持登录状态的唯一方法是重新启动服务器(这不是解决方案)。这很奇怪,因为我认为我的 session 存储配置会正确处理它。我的 config/initializers/session_store.rb
文件包含以下内容:MyApp::Application.config.session_store(ActionDispatch::Session::CacheStore,
:expire_after => 3.days)
我的
production.rb
配置包含:config.cache_store = :dalli_store, ENV["MEMCACHE_SERVERS"],
{
:pool_size => (ENV['MEMCACHE_POOL_SIZE'] || 1),
:compress => true,
:socket_timeout => 0.75,
:socket_max_failures => 3,
:socket_failure_delay => 0.1,
:down_retry_delay => 2.seconds,
:keepalive => true,
:failover => true
}
我正在通过
bundle exec puma -p $PORT -C ./config/puma.rb
启动 puma .我的 puma.rb
包含:threads ENV['PUMA_MIN_THREADS'] || 8, ENV['PUMA_MAX_THREADS'] || 16
workers ENV['PUMA_WORKERS'] || 2
preload_app!
on_worker_boot do
ActiveSupport.on_load(:active_record) do
config = Rails.application.config.database_configuration[Rails.env]
config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
config['pool'] = ENV['DB_POOL'] || 16
ActiveRecord::Base.establish_connection(config)
end
end
那么......这里可能出了什么问题?当密码更改时,如何在不重新启动服务器的情况下更新所有线程/ worker 的 session ?
最佳答案
由于您使用 Dalli 作为 session 存储,因此您可能会遇到此问题。
Multithreading Dalli
从页面:
“如果您使用 Puma 或其他线程应用服务器,从 Dalli 2.7 开始,您可以使用带有 Rails 的 Dalli 客户端池来确保 Rails.cache 单例不会成为线程争用的来源。”
关于ruby-on-rails - 更改密码后用户 session 无效,但仅限于多线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21540085/