随Rack提供的会话管理中间件都基于用于识别用户的cookie。由于我正在开发api,我宁愿将session-id显式地作为查询字符串参数传递。看一下代码库,似乎并没有考虑这个用例,因为所有的会话中间件都是从一个读写/写入cookie的公共类扩展而来。
所以我的问题是 - 是否有一个项目维护备用Rack中间件或机架内置中间件的猴子补丁,这将允许我在查询字符串而不是cookie存储上维护会话ID?
答案 0 :(得分:7)
Rack可以使用自定义会话ID项而不是cookie:
require 'rack/session/abstract/id'
Rack文档可能是一个有用的开始搜索的地方。我相信你正在寻找“跳过”选项(或“推迟”选项)。
文档:
ID为实现基于身份的会话设置了一个基本框架 服务。发送给客户端以维护会话的Cookie只会 包含id引用。只有#get_session和#set_session 需要被覆盖。
所有参数都是可选的。
可以在每个请求的基础上设置这些选项 env中[ 'rack.session.options']。此外,会话的ID可以是 在key:id的选项哈希中找到。这非常不是 建议改变它的价值。
Rack :: Utils :: Context兼容。
默认不包括在内;你必须要求'rack / session / abstract / id'才能使用。
来源:
class ID
DEFAULT_OPTIONS = {
:key => 'rack.session',
:path => '/',
:domain => nil,
:expire_after => nil,
:secure => false,
:httponly => true,
:defer => false,
:renew => false,
:sidbits => 128,
:cookie_only => true,
:secure_random => (::SecureRandom rescue false)
}
我希望这能带给你领导......当你了解更多信息时,你能在这里分享你的成果吗?
神奇的诀窍是将选项:cookie_only => false
与:defer => true
结合起来。当然,标准的Rack :: Session :: Cookie在这里没有多大意义,所以你可以这样做:
use Rack::Session::Pool, :cookie_only => false, :defer => true
有趣的是,您可以在运行时更改选项。在我的用例中,我实际上需要支持传统的基于cookie的机制以及显式参数传递样式,所以我做了以下内容:
class WebApp < Sinatra::Base
configure do
use Rack::Session::Pool, :key => 'session_id'
end
before do
# Switch to parameter based session management if the client is an ios device
if env['HTTP_USER_AGENT'] =~ /iOS/
session.options[:cookie_only] = false
session.options[:defer] = true
end
end
get '/' do
session[:user_id] ||= nil # This triggers a session-write, giving us a valid session-id
body "session_id=#{session.id}"
end
end
答案 1 :(得分:3)
如果您想在API应用程序中消除cookie的使用,但仍想管理会话。例如,在我的情况下,会话标识符来自令牌。
您需要重新定义方法extract_session_id
以从接收的令牌中提取会话标识符。必须在会话存储类上重新定义此方法,因为Rack::Session::Abstract::ID
基于cookie提供默认实现。
它是从Rack::Session::Abstract::ID#current_session_id
方法调用的,它在会话对象上调用#id
方法,通常由Rack::Session::Abstract::SessionHash
实例表示。在最后调用会话存储的SessionHash#id
方法#extract_session_id
中。
我认为将会话标识符提取器独立配置会更简单,但是希望将会话标识符与会话数据一起存储在cookie中导致该欺骗设计。
同样在方法Rack::Session::Abstract::ID
和#commit_session
中查看#set_cookie
类中的Cookie互动有点奇怪。
因此,要完全确定不会设置cookie,您也可以在商店中重新定义#set_cookie
方法。可以通过为会话存储中间件设置cookie_only: false, defer: true
来实现相同的目标,如此答案中所述,但我没有检查过。
当然,您需要修改中间件堆栈以排除与Cookie交互的所有中间件以及可能特定于浏览器的中间件。在默认的rails中间件堆栈上,它可以如下所示:
# config/application.rb
[
Rack::MethodOverride, # browser specific
ActionDispatch::Cookies,
ActionDispatch::Flash
].each do |middleware|
config.middleware.delete(middleware)
end
同样,你肯定需要将会话存储替换为在服务器端存储信息的东西,例如redis,例如:
# config/initializers/session_store.rb
Rails.application.config.session_store ::Custom::Session::TokenRedisStore
就我而言,::Custom::Session::TokenRedisStore
继承::RedisSessionStore
并重新定义了上述所有方法。
::RedisSessionStore
宝石中包含的redis-session-store
。因此,如果您要使用它,显然需要将其添加到Gemfile
。
我是为Rails 4.2.x做的,但是同样的方法可以在任何框架中被采用,Rack
到处都是。