Rails 4 - 设计Omniauth,允许单个用户使用多种社交媒体策略进行身份验证 [英] Rails 4 - Devise Omniauth and allowing a single user to authenticate with multiple social media strategies

查看:150
本文介绍了Rails 4 - 设计Omniauth,允许单个用户使用多种社交媒体策略进行身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Rails 4制作一个应用程序。



我已经尝试(3年以上)了解如何让Devise和Omniauth进行工作,以便用户可以在其用户个人资料中添加多个社交媒体帐户。



我已经阅读了所有的设计和omniauth文档。最好我可以使用这些文档来添加1个单一的社交媒体帐户。这不是我想要的。



我已经尝试过这个网站点教程
sitepoint.com/rails-authentication-oauth-2-0-omniauth

我试过这个willschenck教程
http://willschenk.com/setting-up-devise-with-twitter-and-facebook-and-other-omniauth-我已经尝试过这个jorge.caballeromurillo教程: http://jorge.caballeromurillo.com/multiple-omniauth-providers-for-same-user -on-ruby-on-rails /



我也尝试过这个源代码教程: http://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook - 和利nkedin /



我已经承诺在SO的赏金上成千上万的点,试图找到这个问题的帮助 - 但还没有弄清楚。过去3年来,我一直在我所在地区进行一次轨道会议,并在编码中浪费了$$$,寻求帮助。自从最近令人沮丧的尝试准备好再次走了之后,时间已经过去了。请帮忙。



以下是我到目前为止:



User.rb

  devise:database_authenticatable,:可注册,
:可恢复,可记忆,可追踪,
:可确认,可锁定
# zxcvbnable,
:omniauthable,:omniauth_providers => [:facebook,,linkedin,:twitter,,google_oauth2]

has_many:identity,depend::destroy

def self.find_for_oauth(auth,signed_in_resource = nil)
#获取身份和用户(如果存在)
identity = Identity.find_for_oauth(auth)

#如果提供了signed_in_resource,它将始终覆盖现有用户
#以防止身份被意外创建的帐户锁定。
#请注意,这可能会使僵尸帐户(没有关联的身份)可以在以后清除
#。
user = signed_in_resource? signed_in_resource:identity.user

#p'11111'

#如果需要,创建用户
如果user.nil?
#p 22222
#如果提供商向我们提供经过验证的电子邮件,请通过电子邮件获取现有用户。
#如果没有提供验证的电子邮件,我们会分配一个临时电子邮件,并要求
#用户在下一步通过UsersController.finish_signup
email_is_verified = auth.info.email& amp ; (auth.info.verified || auth.info.verified_email)
email = auth.info.email如果email_is_verified#取出这个,如果stmt为中i的解决方案
user = User.where(:email = >电子邮件).first如果电子邮件

#创建用户,如果它是一个新的注册
如果user.nil?
#p 33333
user = User.new(
#至少有一个问题是每个提供者使用不同的术语来描述名字/姓氏/电子邮件。
first_name:auth.info.first_name,
last_name:auth.info.last_name,
email:email?email:#{TEMP_EMAIL_PREFIX} - #{auth.uid} - #{auth .provider} .com,
#username:auth.info.nickname || auth.uid,
密码:Devise.friendly_token [0,20])
#名称字段的后备 - 添加昵称给用户表
#调试器

#如果email_is_verified
user.skip_confirmation!
#end
#user.skip_confirmation!

user.save!
end
end

#如果需要,将身份与用户关联
如果identity.user!= user
identity.user = user
identity.save!
end
user
end

def email_verified?
self.email&& TEMP_EMAIL_REGEX!〜self.email
end

Identity.rb

  belongs_to:user 
validates_presence_of:uid,:provider
validates_uniqueness_of:uid,:scope =>提供者

def self.find_for_oauth(auth)
find_or_create_by(uid:auth.uid,provider:auth.provider)
end

用户控制器:

  class UsersController< ApplicationController 

before_action:set_user只有:[:show,:edit,:update,,finish_signup,:destroy]

def index
#if params [已批准] ==false
#@users = User.find_all_by_approved(false)
#else
@users = User.all
authorize @users
#end

end

#GET /users/:id.:format
def show
#authorize! :read,@user
end

#GET / users /:id / edit
def edit
#authorize! :update,@user
authorize @user
end


#PATCH / PUT /users/:id.:format
def update
#授权! :update,@user
respond_to do | format |
authorize @user
如果@ user.update(user_params)
sign_in(@user == current_user?@user:current_user,:bypass => true)
#尝试在电子邮件地址(完成注册)后,让用户与组织匹配更新用户模型。
UserOrganisationMapperService.call(@user)

format.html {redirect_to @user}#,注意:'您的个人资料已成功更新'}
format.json {head: no_content}
else
format.html {render action:'edit'}
format.json {render json:@ user.errors,status::unprocessable_entity}
end
end
end

#GET / PATCH / users /:id / finish_signup
def finish_signup
#authorize! :update,@user


如果request.patch? &安培;&安培; params [:user]#&&& params [:user] [:email]
如果@ user.update(user_params)
@ user.skip_reconfirm!
#@ user.confirm!

sign_in(@user,:bypass => true)

redirect_to root_path#,注意:'您的个人资料已成功更新'
#redirect_to [@ user,@ user.profile || @ user.build_profile]
#sign_in_and_redirect(@user,:bypass => true)
else
@show_errors = true
end
end
end

#DELETE /users/:id.:format
def destroy
#authorize! :delete,@user
@ user.destroy
authorize @user
respond_to do | format |
format.html {redirect_to root_url}
format.json {head:no_content}
end
end

private
def set_user
@user = User.find(params [:id])
authorize @user
end

def user_params
#params.require(:user)。 permit(policy(@user).permitted_attributes)
accessible = [:first_name,:last_name,:email,,avatar,{role_ids:[]}]#使用自己的参数扩展
可访问<< ; [:password,:password_confirmation]除非params [:user] [:password] .blank?
#可访问<<< [:approved] if user.admin
params.require(:user).permit(accessible)
end

end
/ pre>

身份控制器

  class IdentitiesController< ApplicationController 
before_action:set_identity,只有:[:show,:edit,:update,:destroy]
before_action:authenticate_user!

#GET / identity
#GET /identities.json
def index
@identities = Identity.all
end

#GET / identity / 1
#GET /identities/1.json
def show
end

#GET / identity / new
def new
@identity = Identity.new
end

#GET / identity / 1 / edit
def edit
end

#POST / identity
#POST /identities.json


def create

@identity = Identity.new(identity_params)

respond_to do | format |
if @ identity.save
format.html {redirect_to @identity,notice:'Identity was successfully created。'}
format.json {render:show,status::created,location: @identity}
else
format.html {render:new}
format.json {render json:@ identity.errors,status::unprocessable_entity}
end
结束
结束

#PATCH / PUT / identity / 1
#PATCH / PUT /identities/1.json

创建替代方案,我也尝试过

  def create 
auth = request.env ['omniauth.auth']
#在这里找到一个身份
@identity = Identity.find_with_omniauth(auth)

如果@ identity.nil?
#如果没有找到任何身份,请在这里创建一个全新的身份
@identity = Identity.create_with_omniauth(auth)
end

如果signed_in?
如果@ identity.user == current_user
#用户已登录,所以他们试图链接一个身份与他们的
#帐户。但是我们发现身份和与之关联的用户
#是当前用户。所以身份已经与
#这个用户相关联。所以让我们来看一个错误信息。
redirect_to root_url,注意:已经链接了该帐户!
else
#该身份与current_user不相关,所以让
#关联身份
@ identity.user = current_user
@ identity.save
redirect_to root_url,通知:成功关联该帐户!
end
else
如果@ identity.user.present?
#我们发现有一个用户关联的身份,所以让我们
#只需要在这里登录
self.current_user = @ identity.user
redirect_to root_url,注意:签名在!
else
#没有用户与身份相关联,所以我们需要创建一个新的
redirect_to new_registration_path,注意:请完成注册
end
end
end

def update

respond_to do | format |
if @ identity.update(identity_params)
format.html {redirect_to @identity,notice:'Identity was successfully updated。'}
format.json {render:show,status::ok ,位置:@identity}
else
format.html {render:edit}
format.json {render json:@ identity.errors,status::unprocessable_entity}
end
end
end

#DELETE / identity / 1
#DELETE /identities/1.json
def destroy
@ identity.destroy
respond_to do | format |
format.html {redirect_to identities_url,notice:'Identity was successfully sold。'}
format.json {head:no_content}
end
end

private
#使用回调来共享动作之间的共同设置或约束。
def set_identity
@identity = Identity.find(params [:id])
end

#永远不要从可怕的互联网信任参数,只允许白名单通过。
def identity_params
params [:identity]
end
end

注册控制器

  class Users :: RegistrationsController< Devise :: RegistrationsController 

before_action:configure_permitted_pa​​rameters,如果::devise_controller?

def create
super do | resource |
UserOrganisationMapperService.call(resource)
end
end




protected

def configure_permitted_pa​​rameters
devise_parameter_sanitizer.for(:sign_up){| u | u.permit(:email,:password,:first_name,,last_name)}
end


private

end

omniauth回调控制器

  class Users :: OmniauthCallbacksController< Devise :: OmniauthCallbacksController 
#sourcey教程------------------

def self.provides_callback_for(provider)
class_eval% Q {
def#{provider}
@user = User.find_for_oauth(env [omniauth.auth],current_user)

如果@ user.persisted?
sign_in_and_redirect @user,event::authentication


else
会话[devise。#{provider} _data] = env [omniauth.auth]
redirect_to new_user_registration_url
end
end
}
end


[:twitter,,facebook,:linkedin,,google_oauth2 ] .each do | provider |
provide_callback_for provider
end



end

用户/完成注册视图

 < div class =container-fluid> 
< div class =row>
< div class =col-xs-8 col-xs-offset-2>
< h1 class =formheader>完成注册< / h1>

<%= form_for(current_user,:as =>'user',:url => finish_signup_path(current_user),:html => {role:'form'}) F | %GT;
<%if @show_errors&&& current_user.errors.any? %GT;

< div id =error_explanation>
<%current_user.errors.full_messages.each do | msg | %GT;
<%= msg%>< br>
<%end%>
< / div>
<%end%>

< div class =form-group>
<! - f.label:false - >
< div class =controls>

<%current_user.first_name.blank? %GT;
<%= f.text_field:first_name,:value => '',class:'form-control input-lg',占位符:'名字'%>
< p class =help-block>你好,你的名字是什么?< / p>
<%end%>

<%if current_user.last_name.blank? %GT;
<%= f.text_field:last_name,:value => '',class:'form-control input-lg',占位符:'姓(姓)'%>
< p class =help-block>添加您的姓氏< / p>
<%end%>


<%if!current_user.email_verified? %GT;
<%= f.text_field:email,:value => '',class:'form-control input-lg',placeholder:'example:email@me.com - 使用你的主要工作或大学地址'%>
< p class =help-block>请确认您的电子邮件地址。无垃圾邮件。< / p>
<%end%>


< / div>
< / div>
< div class =actions>
<%= f.submit'Continue',:class => 'btn btn-primary'%>
< / div>
<%end%>
< / div>
< / div>
< / div>

用户/验证视图

 < div class =container-fluid> 
< div class =row>
< div class =col-xs-8 col-xs-offset-2>
< div class =table-responsivestyle =margin-left:30px; margin-top:15px>
< table class =table table-bordered>

< tr>
< td>< i class =fa fa-facebook>< / i>< / td>
< td>

<%if @ user.identities.map(&:provider).include?('facebook')%>
< span class =glyphicon glyphicon-ok< / span>
<%else%>
<%= link_to图标('Connect Facebook',id:'facebookauth'),user_omniauth_authorize_path(:facebook)%>
<%end%>

< / td>
< / tr>

< tr>
< td>< i class =fa fa-google>< / i>< / td>
< td>
<%if @ user.identities.map(&:provider).include?('googleauth')%>
< span class =glyphicon glyphicon-ok< / span>
<%else%>
<%= link_to图标('Connect Google',id:'googleauth'),user_omniauth_authorize_path(:google_oauth2)%>
<%end%>

< / td>
< / tr>

< tr>
< td>< i class =fa fa-linkedin>< / i>< / td>
< td>
<%if @ user.identities.map(&:provider).include?('linkedin')%>
< span class =glyphicon glyphicon-ok< / span>
<%else%>
<%= link_to图标('Connect Linkedin',id:'linkedinauth'),user_omniauth_authorize_path(:linkedin)%>
<%end%>

< / td>
< / tr>


< tr>
< td>< i class =fa fa-twitter>< / i>< / td>
< td>
<%if @ user.identities.map(&:provider).include?('twitter')%>
å< span class =glyphicon glyphicon-ok< / span>
<%else%>
<%= link_to图标('Connect Twitter',id:'twitterauth'),user_omniauth_authorize_path(:twitter)%>
<%end%>

< / td>
< / tr>

< tr>
< td>密码< / td>
< td>
<%if @ user.encrypted_pa​​ssword.present? %GT;
< span class =glyphicon glyphicon-ok< / span>
<%else%>
<%= form_for(current_user,:as =>'user',:html => {role:'form'})do | f | %GT;
<%if @show_errors&&& current_user.errors.any? %GT;
< div id =error_explanation>
<%current_user.errors.full_messages.each do | msg | %GT;
<%= msg%>< br>
<%end%>
< / div>
< div class =form-group>
< div class =controls>
<%= f.input:password,hint:(#{@ minimum_password_length} characters minimumif @validatable),:input_html => {class:'estimate-password'}%>
< / div>
< / div>
<%end%>
< div class =actions>
<%= f.submit'Continue',:class => 'btn btn-primary'%>
< / div>
<%end%>


< / td>
< / tr>
< / table>
< / div>
< / div>
< / div>
< / div>

路线

  devise_for:users,#class_name:'FormUser',
:controllers => {
:registrations => users / registrations,
#:omniauth_callbacks => users / authentications
:omniauth_callbacks => 'users / omniauth_callbacks'
}


#PER SOURCEY TUTORIAL ----------
match'/ users /:id / finish_signup' => 'users#finish_signup',via:[:get,:patch],:as => :finish_signup

这些都不起作用。我不知道如何插入它。我不知道我是否应该将存储在我的身份表中的属性包含在控制器中的允许的参数中?



属性是:

  t.integeruser_id
t.stringprovider
t.stringaccesstoken
t.stringrefreshtoken
t.stringuid
t.stringname
t.stringemail
t.stringnickname
t.stringimage
t.stringphone
t.stringurls
/ pre>

我有这个工作,所以用户只能用一种方法进行身份验证。我不知道如何让这个工作。我已经尝试了所有的资源,以找出这一点,但我被卡住了。



我已经完成了每个社交插件和电子邮件,但是我没有能够向现有用户添加标识(在当前会话中) ),以便下次登录时,他们可以使用任何可接受的身份。



有人可以帮忙吗?

解决方案

无法看到您的所有代码,我刚刚创建了一个运行多个提供程序的shell应用程序。我刚刚遵循你在 sourcey 。以下是我的回购的链接。



您应该可以克隆它,并通过在devise.rb初始化程序中输入您的应用程序的密钥和秘密令牌,从facebook,twitter和linkedin输入。要使其在本地工作,您需要确保twitter上的回调URL设置为 http://127.0.0.1:3000/



如果您想给用户添加自己的全方位帐户(身份)的选项,而不是通过应用程序授权自动完成,您可以为用户输入表单uid并在控制器或后端创建自己的身份,如下所示:

  new_identity = Identity.new 
new_identity .user_id =当前用户的身份
new_identity.provider =facebook
new_identity.uid =0123456789
new_identity.save!

用户必须从站点获取他们的数字uid,并自己输入。


I am trying to make an app with Rails 4.

I have been trying (for 3+ years) to figure out how to get Devise and Omniauth to works, so that users can add multiple social media accounts to their user profile.

I've read all of the devise and omniauth documentation. The best I can get to with those docs is to add 1 single social media account. That's not what I want.

I've tried this site point tutorial sitepoint.com/rails-authentication-oauth-2-0-omniauth

I've tried this willschenck tutorial http://willschenk.com/setting-up-devise-with-twitter-and-facebook-and-other-omniauth-schemes-without-email-addresses/

I've tried this jorge.caballeromurillo tutorial: http://jorge.caballeromurillo.com/multiple-omniauth-providers-for-same-user-on-ruby-on-rails/

I've also tried this sourcey tutorial: http://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook-and-linkedin/

I've pledged thousands of points in bounties on SO in trying to find help with this problem - but not yet figured it out. I've been to every rails meetup in my area for the last 3 years and wasted $$$ on codementor in trying to find help. Enough time has passed since the most recent frustrating attempt to be ready to give it another go. Please help.

Here's what I have so far:

User.rb

devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable,
          :confirmable, :lockable,
         # :zxcvbnable,
         :omniauthable, :omniauth_providers => [:facebook, :linkedin, :twitter, :google_oauth2 ]

has_many :identities, dependent: :destroy

def self.find_for_oauth(auth, signed_in_resource = nil)
    # Get the identity and user if they exist
    identity = Identity.find_for_oauth(auth)

    # If a signed_in_resource is provided it always overrides the existing user
    # to prevent the identity being locked with accidentally created accounts.
    # Note that this may leave zombie accounts (with no associated identity) which
    # can be cleaned up at a later date.
    user = signed_in_resource ? signed_in_resource : identity.user

    # p '11111'

    # Create the user if needed
    if user.nil?
      # p 22222
      # Get the existing user by email if the provider gives us a verified email.
      # If no verified email was provided we assign a temporary email and ask the
      # user to verify it on the next step via UsersController.finish_signup
      email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
      email = auth.info.email if email_is_verified # take out this if stmt for chin yi's solution
      user = User.where(:email => email).first if email

      # Create the user if it's a new registration
      if user.nil?
        # p 33333
        user = User.new(
          # at least one problem with this is that each provider uses different terms to desribe first name/last name/email. See notes on linkedin above
          first_name: auth.info.first_name,
          last_name: auth.info.last_name,
          email: email ? email : "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com",
          #username: auth.info.nickname || auth.uid,
          password: Devise.friendly_token[0,20])
# fallback for name fields - add nickname to user table
        # debugger

        # if email_is_verified
           user.skip_confirmation!
        # end
        # user.skip_confirmation! 

        user.save!
      end
    end

    # Associate the identity with the user if needed
    if identity.user != user
      identity.user = user
      identity.save!
    end
    user
  end

  def email_verified?
    self.email && TEMP_EMAIL_REGEX !~ self.email
  end

Identity.rb

belongs_to :user
  validates_presence_of :uid, :provider
  validates_uniqueness_of :uid, :scope => :provider

def self.find_for_oauth(auth)
    find_or_create_by(uid: auth.uid, provider: auth.provider)
  end

Users controller:

class UsersController < ApplicationController

before_action :set_user, only: [ :show, :edit, :update, :finish_signup, :destroy]

  def index
    # if params[:approved] == "false"
    #   @users = User.find_all_by_approved(false)
    # else
      @users = User.all
      authorize @users
      # end

  end

  # GET /users/:id.:format
  def show
    # authorize! :read, @user
  end

  # GET /users/:id/edit
  def edit
    # authorize! :update, @user
    authorize @user
  end


  # PATCH/PUT /users/:id.:format
  def update
    # authorize! :update, @user
    respond_to do |format|
      authorize @user
      if @user.update(user_params)
        sign_in(@user == current_user ? @user : current_user, :bypass => true)
        # I'm trying to get the user matched to an organisation after the email address (in finish sign up) updates the user model.
        UserOrganisationMapperService.call(@user)

        format.html { redirect_to @user }#, notice: 'Your profile was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # GET/PATCH /users/:id/finish_signup
  def finish_signup
    # authorize! :update, @user


    if request.patch? && params[:user] #&& params[:user][:email]
      if @user.update(user_params)
        @user.skip_reconfirmation!
        # @user.confirm!

        sign_in(@user, :bypass => true)

        redirect_to root_path#, notice: 'Your profile was successfully updated.'
        # redirect_to [@user, @user.profile || @user.build_profile]
        # sign_in_and_redirect(@user, :bypass => true)
      else
        @show_errors = true
      end
    end
  end

  # DELETE /users/:id.:format
  def destroy
    # authorize! :delete, @user
    @user.destroy
    authorize @user
    respond_to do |format|
      format.html { redirect_to root_url }
      format.json { head :no_content }
    end
  end

  private
    def set_user
      @user = User.find(params[:id])
      authorize @user
    end

    def user_params
      # params.require(:user).permit(policy(@user).permitted_attributes)
      accessible = [ :first_name, :last_name, :email, :avatar, {role_ids: []} ] # extend with your own params
      accessible << [ :password, :password_confirmation ] unless params[:user][:password].blank?
      # accessible << [:approved] if user.admin
      params.require(:user).permit(accessible)
    end

end

Identities controller

class IdentitiesController < ApplicationController
  before_action :set_identity, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

  # GET /identities
  # GET /identities.json
  def index
    @identities = Identity.all
  end

  # GET /identities/1
  # GET /identities/1.json
  def show
  end

  # GET /identities/new
  def new
    @identity = Identity.new
  end

  # GET /identities/1/edit
  def edit
  end

  # POST /identities
  # POST /identities.json


def create

    @identity = Identity.new(identity_params)

    respond_to do |format|
      if @identity.save
        format.html { redirect_to @identity, notice: 'Identity was successfully created.' }
        format.json { render :show, status: :created, location: @identity }
      else
        format.html { render :new }
        format.json { render json: @identity.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /identities/1
  # PATCH/PUT /identities/1.json

create alternative that I have also tried

def create
  auth = request.env['omniauth.auth']
  # Find an identity here
  @identity = Identity.find_with_omniauth(auth)

  if @identity.nil?
    # If no identity was found, create a brand new one here
    @identity = Identity.create_with_omniauth(auth)
  end

  if signed_in?
    if @identity.user == current_user
      # User is signed in so they are trying to link an identity with their
      # account. But we found the identity and the user associated with it 
      # is the current user. So the identity is already associated with 
      # this user. So let's display an error message.
      redirect_to root_url, notice: "Already linked that account!"
    else
      # The identity is not associated with the current_user so lets 
      # associate the identity
      @identity.user = current_user
      @identity.save
      redirect_to root_url, notice: "Successfully linked that account!"
    end
  else
    if @identity.user.present?
      # The identity we found had a user associated with it so let's 
      # just log them in here
      self.current_user = @identity.user
      redirect_to root_url, notice: "Signed in!"
    else
      # No user associated with the identity so we need to create a new one
      redirect_to new_registration_path, notice: "Please finish registering"
    end
  end
end

def update

    respond_to do |format|
      if @identity.update(identity_params)
        format.html { redirect_to @identity, notice: 'Identity was successfully updated.' }
        format.json { render :show, status: :ok, location: @identity }
      else
        format.html { render :edit }
        format.json { render json: @identity.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /identities/1
  # DELETE /identities/1.json
  def destroy
    @identity.destroy
    respond_to do |format|
      format.html { redirect_to identities_url, notice: 'Identity was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_identity
      @identity = Identity.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def identity_params
      params[:identity]
    end
end

registrations controller

class Users::RegistrationsController < Devise::RegistrationsController

  before_action :configure_permitted_parameters, if: :devise_controller?

  def create
    super do |resource|
      UserOrganisationMapperService.call(resource)
    end
  end




  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:email, :password, :first_name, :last_name) }
  end


  private

end

omniauth callbacks controller

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  #sourcey tutorial ------------------

  def self.provides_callback_for(provider)
    class_eval %Q{
      def #{provider}
        @user = User.find_for_oauth(env["omniauth.auth"], current_user) 

        if @user.persisted?
          sign_in_and_redirect @user,  event: :authentication


        else
          session["devise.#{provider}_data"] = env["omniauth.auth"]
          redirect_to new_user_registration_url
        end
      end
    }
  end


  [:twitter, :facebook, :linkedin, :google_oauth2].each do |provider|
    provides_callback_for provider
  end



end

users/finish sign up view

 <div class="container-fluid">
   <div class="row">
    <div class="col-xs-8 col-xs-offset-2">
     <h1 class="formheader">Complete your registration</h1>

        <%= form_for(current_user, :as => 'user', :url => finish_signup_path(current_user), :html => { role: 'form'}) do |f| %>
        <% if @show_errors && current_user.errors.any? %>

          <div id="error_explanation">
          <% current_user.errors.full_messages.each do |msg| %>
            <%= msg %><br>
          <% end %>
          </div>
        <% end %>

    <div class="form-group">
      <!--  f.label :false  -->
      <div class="controls">

        <% if current_user.first_name.blank? %>  
            <%= f.text_field :first_name,  :value => '', class: 'form-control input-lg', placeholder: 'First name' %>
            <p class="help-block">Hi there, what is your first name?.</p>
        <% end %>

        <% if current_user.last_name.blank? %>  
            <%= f.text_field :last_name,  :value => '', class: 'form-control input-lg', placeholder: 'Last name (surname)' %>
            <p class="help-block">Add your last name</p>
        <% end %>    


        <% if !current_user.email_verified? %> 
          <%= f.text_field :email,  :value => '', class: 'form-control input-lg', placeholder: 'Example: email@me.com -- use your primary work or university address' %>
           <p class="help-block">Please confirm your email address. No spam.</p>
        <% end %>   


      </div>
    </div>
    <div class="actions">
      <%= f.submit 'Continue', :class => 'btn btn-primary' %>
    </div>
    <% end %>
    </div>
  </div>
</div>

users/authentications view

<div class="container-fluid">
   <div class="row">
        <div class="col-xs-8 col-xs-offset-2">
            <div class="table-responsive" style="margin-left:30px; margin-top:15px">
                <table class="table table-bordered">

                    <tr>
                      <td><i class="fa fa-facebook"></i></td>   
                      <td>

                        <% if @user.identities.map(&:provider).include?('facebook') %>
                            <span class="glyphicon glyphicon-ok"</span>
                        <% else %>  
                            <%= link_to icon('Connect Facebook', id: 'facebookauth'), user_omniauth_authorize_path(:facebook) %>
                        <% end %>   

                      </td>
                    </tr>

                    <tr>
                      <td><i class="fa fa-google"></i></td> 
                      <td>
                        <% if @user.identities.map(&:provider).include?('googleauth') %>
                            <span class="glyphicon glyphicon-ok"</span>
                        <% else %>  
                            <%= link_to icon('Connect Google', id: 'googleauth'), user_omniauth_authorize_path(:google_oauth2) %>
                        <% end %>   

                      </td>
                    </tr>

                    <tr>
                      <td><i class="fa fa-linkedin"></i></td>   
                      <td>
                        <% if @user.identities.map(&:provider).include?('linkedin') %>
                            <span class="glyphicon glyphicon-ok"</span>
                        <% else %>  
                            <%= link_to icon('Connect Linkedin', id: 'linkedinauth'), user_omniauth_authorize_path(:linkedin) %>
                        <% end %>

                      </td>
                    </tr>


                    <tr>
                      <td><i class="fa fa-twitter"></i></td>    
                      <td>
                        <% if @user.identities.map(&:provider).include?('twitter') %>
å                           <span class="glyphicon glyphicon-ok"</span>
                        <% else %>  
                            <%= link_to icon('Connect Twitter', id: 'twitterauth'), user_omniauth_authorize_path(:twitter) %>
                        <% end %>

                      </td>
                    </tr>

                    <tr>
                      <td>Password</td> 
                      <td>
                        <% if @user.encrypted_password.present? %>
                            <span class="glyphicon glyphicon-ok"</span>
                        <% else %>  
                             <%= form_for(current_user, :as => 'user', :html => { role: 'form'}) do |f| %>
                                <% if @show_errors && current_user.errors.any? %>
                                    <div id="error_explanation">
                                        <% current_user.errors.full_messages.each do |msg| %>
                                            <%= msg %><br>
                                        <% end %>
                                    </div>
                                <div class="form-group">
                                    <div class="controls">  
                                        <%= f.input :password,  hint: ("#{@minimum_password_length} characters minimum" if @validatable), :input_html => { class: 'estimate-password'} %>
                                    </div>
                                </div>      
                            <% end %>
                            <div class="actions">
                                <%= f.submit 'Continue', :class => 'btn btn-primary' %>
                            </div>
                        <% end %>


                      </td>
                    </tr>
                </table>
            </div>  
        </div>
   </div>
</div>    

routes

devise_for :users, #class_name: 'FormUser',
             :controllers => {
                :registrations => "users/registrations",
                # :omniauth_callbacks => "users/authentications"
                :omniauth_callbacks => 'users/omniauth_callbacks'
           }


  # PER SOURCEY TUTORIAL ----------
  match '/users/:id/finish_signup' => 'users#finish_signup', via: [:get, :patch], :as => :finish_signup

None of this works. I don't know how to plug it in. I'm not sure whether I'm supposed to include the attributes stored in my identities table in the permitted params in the controller??

The attributes are:

t.integer  "user_id"
    t.string   "provider"
    t.string   "accesstoken"
    t.string   "refreshtoken"
    t.string   "uid"
    t.string   "name"
    t.string   "email"
    t.string   "nickname"
    t.string   "image"
    t.string   "phone"
    t.string   "urls"

I have got this working so a user can authenticate with one method only. I don't know how to get this working. I've tried every resource I can find to figure this out but I'm stuck.

I have this all working with each individual social plugin and email, but what I don't have is the ability to add identities to an existing user (in a current session) so that the next time they login they can use any acceptable identity.

Can anyone help?

解决方案

Without being able to see all of your code, I just created a shell app that runs with multiple providers. I just followed the steps from the tutorial you mentioned at sourcey. Here is the link to my repo.

You should be able to just clone it and run it by entering your app's keys and secret tokens from facebook, twitter, and linkedin in the devise.rb initializer. To get this to work locally you will need to make sure that the callback url on twitter is set to http://127.0.0.1:3000/.

If you wanted to give a user the option to add their own omniauth account (identity) instead of having it done automatically through app authorization you could just make a form for the user to enter the numeric uid and create the identity your self in the controller or back end like this:

new_identity = Identity.new
new_identity.user_id = "current user's id"
new_identity.provider = "facebook"
new_identity.uid = "0123456789"
new_identity.save!

The user would have to get their numeric uid from the site and enter it themselves.

这篇关于Rails 4 - 设计Omniauth,允许单个用户使用多种社交媒体策略进行身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆