Rails ActiveRecord 存储和新会话 [英] Rails ActiveRecord store and new session

查看:16
本文介绍了Rails ActiveRecord 存储和新会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am new to Rails and experience a strange issue I don't understand. I use ActiveRecord as a session store and need to add session id as a property of JSON responses for all the requests. I use Devise as well if it have some impact on the situation. The problem is that if a request is made by a user without cookies (or at least without session id in the cookie) the session.id is empty or - attention, please - not the same value that is set in the response cookie.

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

For debugging, I add this code as an after_filter to ApplicationController:

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

两个值相同.如果 cookie 存在,它们将匹配 cookie 中的值.否则,如果 cookie 中不存在 session id,则在该请求之后设置的 cookie 具有不同的值.

Both values are the same. They match the value in the cookie if it is present. Otherwise, if session id is not present in the cookie, the cookie set after that request has different value.

我的观点是 session_id 在实际保存到数据库后会获得新值,它必须是唯一的.数据库迁移:

My opinion is that session_id gets new value after it is actually saved to the database, where it have to be unique. DB migration:

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.id 值?

My question: How can I get the actual session.id value of a new session before the first response is rendered?

UPD:

我刚刚创建了一个新的 Rails 应用程序,它使用 ActiveRecord 会话存储而没有设计,我可以在使用此代码 ID 应用程序控制器响应之前获取将在 cookie 中设置的 session.id:

I just created a new Rails app that uses ActiveRecord session store without Devise, and I can get session.id that is going to be set in cookie just before response with this code id application controller:

class ApplicationController < ActionController::Base
  after_filter :show_session

  def show_session
    puts session.id
  end
end

但是在我现有的带有 Devise 的应用程序中,我得到了一个看起来像会话 ID 的值,但它与通过 Set-Cookie 响应标头在 cookie 中设置的值和实际保存到数据库会话表中的值不匹配.看起来 Devise 在某些方面与 ActiveRecord 会话存储存在冲突.需要深入了解一下.

But in my existing app with Devise I get a value that really looks like a session id, but that doesn't match the value set in the cookie via Set-Cookie response header and the value actually saved to sessions table in database. Looks like Devise have a conflict with ActiveRecord session store in some way. Need to go deeper to figure it out.

UPD 2

看起来我找到了问题的根源.正如我所说,我使用 Devise 与 Omniauth 进行授权.根据文档,出于安全原因,sign_in 方法会重置会话 ID.但是在重置 session.id 返回旧值之后,该值已自动设置.我将此代码用作 Omniauth 回调:

Looks like I found the problem roots. As I said, I use Devise for authorization with Omniauth. According to the documentation, sign_in method resets session id for security reasons. But after that reset session.id returns the old value, that had been automatically set. I use this code as an Omniauth callback:

def facebook_access_token
  sign_in @user
  puts session.id
end

在控制台中,我得到的会话 ID 与 Set-Cookie 响应标头中设置的会话 ID 不同.如果我注释sign_in"行,则这些值匹配.新问题:在 sign_in 方法内部重置后,如何获取新的会话 ID 值?是内部 Warden/Devise 实现还是什么?

And in console I get session id different from the one set in the Set-Cookie response header. If I comment "sign_in" line, these values match. New question: how can I get the new session id value after it is been reset inside of sign_in method? Is it an internal Warden/Devise implementation or something?

推荐答案

我遇到的问题是由默认 Warden 配置引起的.它更新了会话 ID,但不知何故无法通过 session.id 访问新 ID.

The problem I experienced was caused by default Warden configuration. It renewed session id, but somehow the new id was not accessible via session.id.

我发现阻止这种行为的唯一方法是将此代码放入 config/initializers/devise.rb:

The only way I found to stop this behavior was putting this code into config/initializers/devise.rb:

Warden::Manager.after_set_user do |user,auth,opts|
  auth.env["rack.session.options"][:renew] = false
end

出于安全原因,这种方法可能不是很好,但我在搜索和阅读资源的一周内没有其他想法.

Probably this method is not really good for security reasons, but I have no other ideas in a week of searching and reading sources.

这篇关于Rails ActiveRecord 存储和新会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆