【发布时间】:2014-09-30 04:11:00
【问题描述】:
注意:原来的问题有所改变。我找到了两个解决方案,并且可能正在完全改变设计。
无论如何,我很想知道,为什么 RequestStore 不起作用(是因为 Warden 在中间件堆栈中截获了前面的消息吗?),Thread.current 是如何工作的,以及为什么实例变量是一个不稳定的解决方案.
我已在我的应用程序中使用 default_scope 启用多租户,包括设计用户模型。
在application_controller.rb中,我有
around_filter :set_request_store
def set_request_store
Tenant.current = current_tenant.id
yield
ensure
Tenant.current = nil
end
Tenant.current 依次设置 RequestStore 哈希键。
在tenant.rb中
def self.current
RequestStore.store[:current_tenant_id]
end
def self.current=(tenant_id)
RequestStore.store[:current_tenant_id] = tenant_id
end
在我的 routes.rb 文件中,我有以下内容
unauthenticated do
root to: 'home#index', as: :public_root
end
authenticated :user do
root to: 'dashboard#index', as: :application_root
end
通过日志更好地说明了我面临的问题。
成功登录后。
Started POST "/users/sign_in" for 127.0.0.1 at 2014-09-24 14:57:13 +0530
Processing by Devise::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"[FILTERED]", "user"=>{"tenant_id"=>"1", "email"=>"user@example.com", "password"=>"[FILTERED]"}}
Tenant Load (0.9ms) SELECT "tenants".* FROM "tenants" WHERE "tenants"."subdomain" = 'test' ORDER BY "tenants"."id" ASC LIMIT 1
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."tenant_id" = 1 AND "users"."email" = 'user@example.com' ORDER BY "users"."id" ASC LIMIT 1
(0.2ms) BEGIN
SQL (0.5ms) UPDATE "users" SET "current_sign_in_at" = $1, "last_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = 1 [["current_sign_in_at", "2014-09-24 09:27:13.553818"], ["last_sign_in_at", "2014-09-24 09:26:31.548568"], ["sign_in_count", 44], ["updated_at", "2014-09-24 09:27:13.556155"]]
(1.1ms) COMMIT
Devise 将应用程序重定向到(应用程序)根路径。实际上,公共和应用程序根的路径是相同的。
Redirected to http://test.com.dev/
Completed 302 Found in 90ms (ActiveRecord: 3.4ms)
路由中未经身份验证的方法调用(可能)试图对用户进行身份验证(在中间件的某处使用 Warden ???)并且此时未设置tenant_id。请参阅 tenant_id 的 WHERE 子句。
Started GET "/" for 127.0.0.1 at 2014-09-24 14:57:13 +0530
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."tenant_id" IS NULL AND "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Processing by HomeController#index as HTML
有没有人遇到过这样的问题并解决了?
解决方案 1:
首先,我使用 Thread.current 解决了这个问题。由于某种原因,RequestStore.store 没有在 Devise 方法中设置。
以下代码解决了登录问题。但是,我找不到安全地取消设置 Thread.current 上的值的地方。
在user.rb中
devise ...,
request_keys: [:subdomain]
default_scope { where(tenant_id: (Tenant.current || Thread.current[:current_tenant_id])) }
protected
def self.find_for_authentication(warden_conditions)
subdomain = warden_conditions.delete(:subdomain)
Thread.current[:current_tenant_id] = Tenant.where(subdomain: subdomain).first.id
super
end
解决方案 2:
更新:这也有问题。这并不总是有效。
改用实例变量。
在user.rb中
devise ...,
request_keys: [:subdomain]
default_scope { where(tenant_id: (Tenant.current || @tenant_id)) }
protected
def self.find_for_authentication(warden_conditions)
subdomain = warden_conditions.delete(:subdomain)
@tenant_id = Tenant.where(subdomain: subdomain).first.id
super
end
我想知道哪种方法更安全,或者是否有更好的方法来解决这个问题。
【问题讨论】:
标签: ruby-on-rails devise multi-tenant