使用OmniAuth为多租户Rails 5应用程序设计身份验证

3
这里是情况。我正在使用apartment 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 API会返回某种形式的user_id吧?这就是你需要开始的地方。 - CottonEyeJoe
不幸的是,由于可能存在的模式,这可能是不可能的。如果我有模式AB,每个模式都可以有一个user.id == 1的用户。 - Will
2个回答

5
所以结果证明,答案是在授权链接中传递参数,这些参数最终通过request.env ["omniauth.params"]传递给回调操作。 授权链接格式: 在这里,我遇到了在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 使用 Devise、Twitter、Facebook 和 LinkedIn 的 OmniAuth。我的主要目的是让回调控制器位于空白子域中,这样我只需给我的 LinkedIn 开发应用一个回调 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

1

你能否将每个域名都注册为与Linkedin的回调函数(如果你有很多,那么这会很快变得难以管理)... 在将用户发送到Linkedin之前,你可以对其进行cookie操作,因此当他们返回时,你知道他们属于哪个子域。


不幸的是,子域名是动态生成的。然而,cookie 的想法很有趣,可能会有用。 - Will

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接