【问题标题】:Rails 4, Devise, Omniauth (with multiple providers)Rails 4、Devise、Omniauth(有多个供应商)
【发布时间】:2014-02-10 13:15:28
【问题描述】:

我花了几天时间观看有关设计和omniauth 的RailsCasts,然后阅读相关教程以设置使用这些gem 的身份验证系统。我认为 RailsCasts 已经过时了,试图弥补与其他教程的差距会产生各种问题。

请任何人推荐一个当前的教程,我可以将其用作实现该系统的基础。我有单独的用户和身份验证模型(用户有很多身份验证)。

我真的很想在 rails 4 上使用 devise 和 omniauth(使用 CanCan 来获得能力),但在尝试找到基本设置(使用 psql 作为数据库)时我费尽心思。

【问题讨论】:

  • 官方文档是要走的路
  • 我也遇到了同样的问题...有什么解决办法吗?
  • 我发现了这个:github.com/mohitjain/social-login-in-rails,但我认为它不能解决从 Twitter 链接用户/身份验证的问题。 Twitter 不共享电子邮件,他的用户模型使用电子邮件来查找以前的记录。嗯……希望有人能找到解决这一切的好办法。
  • Railscasts 有点过时了(修改后的稍微好一点),但你应该仍然可以使用它们来实现 Devise + OmniAuth。究竟是什么问题?

标签: ruby-on-rails devise omniauth


【解决方案1】:

要将 Devise 与多个身份验证提供程序一起使用,您还需要 1 个模型 - 授权

#authorization.rb

# == Schema Information
#
# Table name: authorizations
#
#  id           :integer          not null, primary key
#  user_id      :integer
#  provider     :string(255)
#  uid          :string(255)
#  token        :string(255)
#  secret       :string(255)
#  created_at   :datetime
#  updated_at   :datetime
#  profile_page :string(255)
#

class Authorization < ActiveRecord::Base
  belongs_to :user
end

用户模型有代码

#user.rb

SOCIALS = {
  facebook: 'Facebook',
  google_oauth2: 'Google',
  linkedin: 'Linkedin'
}


has_many :authorizations

def self.from_omniauth(auth, current_user)
  authorization = Authorization.where(:provider => auth.provider, :uid => auth.uid.to_s, 
                                      :token => auth.credentials.token, 
                                      :secret => auth.credentials.secret).first_or_initialize
  authorization.profile_page = auth.info.urls.first.last unless authorization.persisted?
  if authorization.user.blank?
    user = current_user.nil? ? User.where('email = ?', auth['info']['email']).first : current_user
    if user.blank?
      user = User.new
      user.skip_confirmation!
      user.password = Devise.friendly_token[0, 20]
      user.fetch_details(auth)
      user.save
    end
    authorization.user = user
    authorization.save
  end
  authorization.user
end

def fetch_details(auth)
  self.name = auth.info.name
  self.email = auth.info.email
  self.photo = URI.parse(auth.info.image)
end

最后你需要重写设计控制器的方法

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def all
    user = User.from_omniauth(env['omniauth.auth'], current_user)
    if user.persisted?
      sign_in user
      flash[:notice] = t('devise.omniauth_callbacks.success', :kind => User::SOCIALS[params[:action].to_sym])
      if user.sign_in_count == 1
        redirect_to first_login_path
      else
        redirect_to cabinet_path
      end
    else
      session['devise.user_attributes'] = user.attributes
      redirect_to new_user_registration_url
    end
  end

  User::SOCIALS.each do |k, _|
    alias_method k, :all
  end
end

如果您需要一些供应商,例如Twitter 你需要重写 twitter 方法,因为它不提供用户电子邮件,你应该以其他方式保存它的凭据。

你也应该在路线上做一些改变

devise_for :users,
           :controllers => {
             :omniauth_callbacks => 'users/omniauth_callbacks',
           }

【讨论】:

  • 感谢分享代码!请注意,授权与身份验证不同,omniauth 关心的是用户身份验证(你是谁),而像 pundit 和 can 之类的 gem 可以处理授权(我们知道你是谁,这是你能做什么和不能做什么)。只是为了向编程新手澄清一些事情。
  • 非常感谢您。实际上很难找到一个完整的、有效的、最新的解决方案。
  • users 下嵌套omniauth 回调有什么作用,为什么有必要?
  • 没必要,但在我的项目中,设计控制器经常有很多变化,所以我认为最好将它们存储在单独的文件夹中。
  • 如果我也有本地登录怎么办。如果我的本地登录的电子邮件 ID 相同,则会给出电子邮件已被接收的错误
【解决方案2】:

你应该试试这个宝石。 https://github.com/AlexanderZaytsev/domp 快速且易于集成。我在大约 30m 处有一个工作设置。

【讨论】:

  • 那个宝石不适合我。你能分享你的例子吗?
  • 我正在使用这个 gem。不过有一个小问题。当我转到 (localhost:3000/users/auth/facebook) 时,它没有给我路由匹配错误。但是使用 rake 命令我可以看到它是在那里定义的
【解决方案3】:

在你的初始化器中尝试做这样的事情

#config/initializers/devise.rb
  #provider1
  config.omniauth :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_SECRET'],
    :site => 'https://graph.facebook.com/',
    :authorize_path => '/oauth/authorize',
    :access_token_path => '/oauth/access_token',
    :scope => 'email, user_birthday, read_stream, read_friendlists, read_insights, read_mailbox, read_requests, xmpp_login, user_online_presence, friends_online_presence, ads_management, create_event, manage_friendlists, manage_notifications, publish_actions, publish_stream, rsvp_event, user_about_me, user_activities, user_birthday, user_checkins, user_education_history, user_events, user_groups, user_hometown, user_interests, user_likes, user_location, user_notes, user_photos, user_questions, user_relationships, user_relationship_details, user_religion_politics, user_status, user_subscriptions, user_videos, user_website, user_work_history'

  #provider2
  config.omniauth :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'],
    :scope => {
     :secure_image_url => 'true',
     :image_size => 'original',
     :authorize_params => {
       :force_login => 'true'
     }
   }

  #provider3
  config.omniauth :google_oauth2, ENV["GOOGLE_KEY"], ENV["GOOGLE_SECRET"]

【讨论】:

  • 这对我来说无法强制 Twitter 让用户重新登录。它使用与我之前在浏览器上登录时相同的帐户。我正在努力让用户可以将多个帐户链接到他们的站点帐户。
  • 您可以创建一个auth controller,它属于一个用户并且一个用户拥有_many auths
  • 我找到了答案。取出:scope =&gt;,使用omniauth-twitter gem 就可以正常工作。 scope 适用于 Facebook 和其他一些服务。
  • 很高兴你找到了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-27
  • 2014-09-25
  • 2013-10-29
  • 2016-02-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多