【问题标题】:Devise with Omniauth for multiple models without STI使用 Omniauth 为没有 STI 的多个模型设计
【发布时间】:2012-07-02 00:00:10
【问题描述】:

有没有办法为没有 STI 的多个模型配置 Devise Omniauth?

我们有 Student 和 Professors 模型,我们不想使用 STI,但现在我们意识到 Devise with Omniauth 不能很好地处理多个模型。

.rvm/gems/ruby-1.9.3-p125/gems/devise-2.1.0/lib/devise/rails/routes.rb:384:in `devise_omniauth_callback': Wrong OmniAuth configuration. If you are getting this exception, it means that either: (RuntimeError)

1) You are manually setting OmniAuth.config.path_prefix and it doesn't match the Devise one
2) You are setting :omniauthable in more than one model
3) You changed your Devise routes/OmniAuth setting and haven't restarted your server

【问题讨论】:

  • 在这里遇到同样的问题。我目前正在考虑手动连接 facebook 身份验证。 =/
  • 我们使用了一个父类 User,它使用 Devise Omniauth 进行身份验证,然后是从 User 扩展的其他模型。没找到其他的...
  • @marc_ferna 除非您在代码中添加一些逻辑更改,否则它不会直接工作。

标签: ruby-on-rails devise omniauth


【解决方案1】:

您好,我来这里遇到了类似的问题,我遇到了这个解决方案,也许我会帮助下一个。 在我的情况下,我有两个设计模型,我以不同的方式使用omniauth,我的第一个模型是可以通过普通设计注册或omniauth登录的用户,第二个是艺术家,他可以通过常规注册唱出表格,但我仍然需要omniauth来验证来自twitter的值,验证字段(对twitters个人资料的小检查意味着一个著名的用户是否真的是那个人)。

所以当我来的时候,我不能有两个设计的omniauthable模型,我只是决定对两者使用相同的omniauth。

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def all
    if artist_signed_in? and session["devise.authorize"] == current_artist.email
      session["devise.authorize"] = nil
      if current_artist.artist_profile.update_from_omniauth(request.env["omniauth.auth"])
        if current_artist.artist_profile.verified
          flash[:notice] = "You were verified"
        else
          flash[:alert] = "Twitter go well but you aren't verified there"
        end
        redirect_to edit_artist_profile_path(current_artist.artist_profile)
      else
        flash[:error] = "We can't connect with #{request.env["omniauth.auth"].provider.titleize.split(" ").first}"
        redirect_to edit_artist_profile_path(current_artist.artist_profile)
      end
    elsif !user_signed_in?
      user = User.from_omniauth(request.env["omniauth.auth"])
      if user.persisted?
        flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => user.provider.titleize.split(" ").first
        user.user_profile.from_omniauth(request.env["omniauth.auth"])
        sign_in_and_redirect user, :event => :authentication
      else
        session["count_errors"] = 0 if session["devise.user_attributes"] == nil
        session["devise.user_attributes"] = user.attributes
        redirect_to new_user_registration_url
      end
    else
      flash[:notice] = "You are already log in #{current_user.email}"
      redirect_to root_path
    end
  end

  def after_omniauth_failure_path_for(scope)
    if artist_signed_in? and session["devise.authorize"] == current_artist.email
      session["devise.authorize"] = nil
      edit_artist_profile_path(current_artist.artist_profile)
    else
      super
    end
  end

  alias_method :twitter, :all
end

对于第一种情况,普通用户,我们有

elsif !user_signed_in?

它将执行正常的过程,一切都像每个指南一样,但对于第二种情况(已验证的字段和艺术家资料),我发送了一个带有一些随机值的小会话

session["devise.authorize"]

然后我用我的艺术家个人资料控制器中的新路线调用链接

<%= link_to "Verify with Twitter", artist_profiles_integrate_twitter_path %>

谁加载会话并重定向到用户omniauth路由

class ArtistProfilesController < ApplicationController
   ...
   def integrate_twitter
      session["devise.authorize"] = current_artist.email
      redirect_to user_omniauth_authorize_path(:twitter)
   end
 end

然后我在每个类中定义了几个使用omniauth的方法,第一个创建用户(基于railscast剧集“devise-omniauth-revised”),第二个只是更新我的艺术家档案模型上的字段,你应该覆盖 after_omniauth_failure_path_for(scope),这只是返回登录失败的路径,使用与更改后错误路径相同的技术(例如,当无法与 twitter 连接时,它将重定向到用户注册路径和会话会存在一段时间)我们可以有正常的行为并在所有情况下清理会话。

希望对您有所帮助,问候!

【讨论】:

    【解决方案2】:

    目前,Devise 的 Omniauthable 模块不适用于多个模型。 (https://github.com/plataformatec/devise/wiki/OmniAuth-with-multiple-models) 简而言之,您需要停止依赖设计通过“omniauthable”来发挥其魔力,并手动完成。这并不复杂,一旦你让第一个模型在 middelware 上工作,那么很明显如何扩展多个模型,因为它归结为具有不同模型名称的完全相同的代码。

    需要的步骤:

    1. 从 devise.rb 和使用的模型中删除 omniauthable 和 devise omniauth 设置
    2. 包含 oauth 作为中间件(这样您就可以在请求到达 Rails 之前捕获它)
    3. 编写手动路线 - 简单易行
    4. 处理响应 - 显示您现在拥有的相同代码
    5. 处理失败场景(在 oauth 提供程序上被拒绝) - middelware 设置中的另一个块

    我解决了类似的问题,我在这里有详细的解释:https://blog.kodius.io/2016/12/20/devise-omniauth-multiple-models/ 中间件 oauth 设置的代码在这里:https://github.com/kodius/oauth-example-multiple-models

    【讨论】:

      【解决方案3】:

      目前,Devise 的 Omniauthable 模块不适用于多个模型。不过不用担心,因为 Omniauthable 模块只是 OmniAuth 的简单包装器。

      https://github.com/plataformatec/devise/wiki/OmniAuth-with-multiple-models

      【讨论】:

        【解决方案4】:

        我认为与其将:omniauthable 写给个人StudentProfessor model。您应该生成第三个模型,例如 Omniuser,并为其添加 :omniauthable 设置。

        class Student < ActiveRecord::Base
          has_one :omniuser
        end
        
        class Professor < ActiveRecord::Base
          has_one :omniuser
        end
        

        【讨论】:

        • 这是我们最终使用的方法,但它是单表继承,是我们想要避免的
        • @marc_ferna 实际上我并不是在建议 STI 方法,而是建议使用另一个 omniuser 模型来保存 ominiauth 的东西。
        • 感谢您的回答。我可能误解了 STI 是什么或您的解决方案,但基于 this article,此解决方案将涉及具有 emailpassword 等属性的模型 omniauth,以及将具有的模型 student自己的属性。这两个模型(及其属性)将是我们数据库中的一个表(professor 也是如此)。是对的吗?如果我误解了您的回答,请进一步解释;)
        • @marc_ferna - 您能否详细说明您是如何为 STI 创建 devise 与 omniauth 模型的?我有同样的问题,我们有三个独立的用户模型,其中两个需要omniauth-facebook。真的对模型和路线设置感到困惑
        猜你喜欢
        • 2013-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-08
        • 2013-03-23
        相关资源
        最近更新 更多