gpt4 book ai didi

ruby-on-rails - Rails ActiveRecord存储和新 session

转载 作者:行者123 更新时间:2023-12-04 05:49:49 32 4
gpt4 key购买 nike

我是Rails的新手,遇到了一个我不理解的奇怪问题。
我将ActiveRecord用作 session 存储,并且需要为所有请求添加 session ID作为JSON响应的属性。如果对情况有一定影响,我也会使用Devise。问题是,如果请求是由没有Cookie(或至少没有Cookie中的 session ID)的用户发出的,则session.id为空或-请注意-请不要在响应Cookie中设置相同的值。

为了进行调试,我将此代码作为after_filter添加到ApplicationController中:

puts session.id
puts request.session_options[:id]

这两个值是相同的。它们与cookie中的值(如果存在)匹配。否则,如果cookie中不存在 session ID,则在该请求之后设置的cookie具有不同的值。

我的看法是,session_id在实际保存到数据库之后必须获取新值,该数据库必须是唯一的。数据库迁移:
def change
create_table :sessions do |t|
t.string :session_id, :null => false
t.text :data
t.timestamps
end

add_index :sessions, :session_id, :unique => true
add_index :sessions, :updated_at
end

我的问题:如何在呈现第一个响应之前获取新 session 的实际session.id值?

UPD:

我刚刚创建了一个新的Rails应用程序,该应用程序使用的ActiveRecord session 存储没有Devise,我可以在要使用此代码ID应用程序 Controller 进行响应之前获取将在cookie中设置的session.id:
class ApplicationController < ActionController::Base
after_filter :show_session

def show_session
puts session.id
end
end

但是在使用Devise的现有应用程序中,我得到的值确实看起来像 session ID,但与通过Set-Cookie响应 header 在cookie中设置的值和实际保存到数据库中session表的值不匹配。看起来Devise在某种程度上与ActiveRecord session 存储有冲突。需要更深入地了解它。

UPD 2

看来我找到了问题的根源。就像我说的,我使用Devise通过Omniauth进行授权。根据文档,出于安全原因,sign_in方法重置 session ID。但是,在该重置session.id返回旧值之后,该值已被自动设置。我将此代码用作Omniauth回调:
def facebook_access_token
sign_in @user
puts session.id
end

在控制台中,我获得的 session ID与Set-Cookie响应 header 中的 session ID不同。如果我在“sign_in”行中注释,则这些值匹配。新问题:在sign_in方法内将新的 session ID值重置后,如何获取?它是内部的Warden/Devise实现还是其他?

最佳答案

更新仍然很重要,您不应该禁用它

此外,在 Controller 执行后也会生成新的 session ID,因此有机会设置要发送给客户端的响应之后。

解决方案是手动触发 session ID的更新

在您的ApplicationController中添加方法:

protected

def commit_session_now!
return unless session.options[:renew]

object = session.options.instance_variable_get('@by')
env = session.options.instance_variable_get('@env')
session_id = object.send(:destroy_session, env, session.id || object.generate_sid, session.options)

session_data = session.to_hash.delete_if { |k,v| v.nil? }
object.send(:set_session, env, session_id, session_data, session.options)

session.options[:renew] = false
session.options[:id] = session_id
end

然后在您的 Controller 中,您只需在获取响应的 session ID之前调用此方法
def my_action
...
commit_session_now!
render json: {session_id: session.id}, status: :ok
end
commit_session_now!中的代码来自 Rack::Session::Abstract::ID#commit_session https://github.com/rack/rack/blob/master/lib/rack/session/abstract/id.rb#L327

关于ruby-on-rails - Rails ActiveRecord存储和新 session ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18609844/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com