使用多租户设计 OmniAuth Rails 5 应用程序
Devise OmniAuth with a Multi-tenant Rails 5 App
情况是这样的。我有一个使用公寓 gem 的多租户 rails 应用程序,我需要在其中实施 LinkedIn OmniAuth 策略。
正如您在我的路线中所见,Devise 用户和相关路线仅保留在子域的各个模式中。
示例路线:
好:https://frank.example.io/users/sign_in
差:https://example.io/users/sign_in
路线
class SubdomainPresent
def self.matches?(request)
request.subdomain.present?
end
end
class SubdomainBlank
def self.matches?(request)
request.subdomain.blank?
end
end
Rails.application.routes.draw do
constraints(SubdomainPresent) do
...
devise_for :users, controllers: {
omniauth_callbacks: 'omniauth_callbacks'
}
devise_scope :user do
get '/users/:id', to: 'users/registrations#show', as: "show_user"
end
...
end
end
我的具体问题是 LinkedIn 不支持带有回调 URL 的通配符,所以我不知道如何在 OAuth 身份验证后将用户定向到正确的域。
你能否将每个域注册为链接的回调(我想如果你有很多很快就会变得难以管理)。你可以在将用户发送到 linkedin 之前对用户进行 cookie,这样当他们 return 你知道他们属于哪个子域。
所以答案是在授权中传递参数 link 最终会通过 request.env["omniauth.params"]
传递给回调操作
授权Link格式:
在这里,我在将参数添加到 Devise URL 构建器时遇到了问题,所以我只是手动添加了参数。这可能会被移动到 url 助手
<%= link_to "Connect your Linkedin", "#{omniauth_authorize_path(:user, :linkedin)}?subdomain=#{request.subdomain}" %>
路线:
然后我定义了一个由指向回调操作的空白子域约束的路由。
class SubdomainPresent
def self.matches?(request)
request.subdomain.present?
end
end
class SubdomainBlank
def self.matches?(request)
request.subdomain.blank?
end
end
Rails.application.routes.draw do
constraints(SubdomainPresent) do
...
devise_for :users, controllers: {
omniauth_callbacks: 'omniauth_callbacks'
}
resources :users
...
end
constraints(SubdomainBlank) do
root 'welcome#index'
...
devise_scope :user do
get 'linkedin/auth/callback', to: 'omniauth_callbacks#linkedin'
end
...
end
end
控制器:
我使用本教程设置了我的回调控制器:Rails 4 OmniAuth using Devise with Twitter, Facebook and Linkedin。我的回调控制器主要 objective 是让它驻留在空白子域中,因此我只需要向我的 LinkedIn Dev App 返回一个回调 URL。使用此控制器,我在 omniauth 参数中搜索子域参数,并使用它切换到正确的模式。
def self.provides_callback_for(provider)
class_eval %Q{
def #{provider}
raise ArgumentError, "you need a subdomain parameter with this route" if request.env["omniauth.params"].empty?
subdomain = request.env["omniauth.params"]["subdomain"]
Apartment::Tenant.switch!(subdomain)
...
end
}
end
情况是这样的。我有一个使用公寓 gem 的多租户 rails 应用程序,我需要在其中实施 LinkedIn OmniAuth 策略。
正如您在我的路线中所见,Devise 用户和相关路线仅保留在子域的各个模式中。
示例路线:
好:https://frank.example.io/users/sign_in
差:https://example.io/users/sign_in
路线
class SubdomainPresent
def self.matches?(request)
request.subdomain.present?
end
end
class SubdomainBlank
def self.matches?(request)
request.subdomain.blank?
end
end
Rails.application.routes.draw do
constraints(SubdomainPresent) do
...
devise_for :users, controllers: {
omniauth_callbacks: 'omniauth_callbacks'
}
devise_scope :user do
get '/users/:id', to: 'users/registrations#show', as: "show_user"
end
...
end
end
我的具体问题是 LinkedIn 不支持带有回调 URL 的通配符,所以我不知道如何在 OAuth 身份验证后将用户定向到正确的域。
你能否将每个域注册为链接的回调(我想如果你有很多很快就会变得难以管理)。你可以在将用户发送到 linkedin 之前对用户进行 cookie,这样当他们 return 你知道他们属于哪个子域。
所以答案是在授权中传递参数 link 最终会通过 request.env["omniauth.params"]
授权Link格式:
在这里,我在将参数添加到 Devise URL 构建器时遇到了问题,所以我只是手动添加了参数。这可能会被移动到 url 助手
<%= link_to "Connect your Linkedin", "#{omniauth_authorize_path(:user, :linkedin)}?subdomain=#{request.subdomain}" %>
路线:
然后我定义了一个由指向回调操作的空白子域约束的路由。
class SubdomainPresent
def self.matches?(request)
request.subdomain.present?
end
end
class SubdomainBlank
def self.matches?(request)
request.subdomain.blank?
end
end
Rails.application.routes.draw do
constraints(SubdomainPresent) do
...
devise_for :users, controllers: {
omniauth_callbacks: 'omniauth_callbacks'
}
resources :users
...
end
constraints(SubdomainBlank) do
root 'welcome#index'
...
devise_scope :user do
get 'linkedin/auth/callback', to: 'omniauth_callbacks#linkedin'
end
...
end
end
控制器:
我使用本教程设置了我的回调控制器:Rails 4 OmniAuth using Devise with Twitter, Facebook and Linkedin。我的回调控制器主要 objective 是让它驻留在空白子域中,因此我只需要向我的 LinkedIn Dev App 返回一个回调 URL。使用此控制器,我在 omniauth 参数中搜索子域参数,并使用它切换到正确的模式。
def self.provides_callback_for(provider)
class_eval %Q{
def #{provider}
raise ArgumentError, "you need a subdomain parameter with this route" if request.env["omniauth.params"].empty?
subdomain = request.env["omniauth.params"]["subdomain"]
Apartment::Tenant.switch!(subdomain)
...
end
}
end