加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby-on-rails – Rails 4 – 设计Omniauth并允许单个用户通过多

发布时间:2020-12-17 02:25:45 所属栏目:百科 来源:网络整理
导读:我正在尝试用Rails 4创建一个应用程序. 我一直在尝试(3年)弄清楚如何使Devise和Omniauth工作,以便用户可以在他们的用户配置文件中添加多个社交媒体帐户. 我已经阅读了所有的设计和omniauth文档.我可以使用这些文档获得的最佳效果是添加1个单独的社交媒体帐户
我正在尝试用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-schemes-without-email-addresses/

我试过这个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-and-linkedin/

在试图找到这个问题的帮助时,我已经在SO上承诺了数以千计的积分 – 但还没有想出来.在过去的3年里,我去过我所在地区的每一次铁路聚会,并且在代理商上试图找到帮助时浪费了$$$.自最近一次令人沮丧的尝试准备再给它一次以来,已经过去了足够的时间.请帮忙.

这是我到目前为止所拥有的:

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 '22222'

    # 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

用户控制器:

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

身份控制器

class IdentitiesController < ApplicationController
  before_action :set_identity,only: [:show,: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

创造我也尝试过的替代方案

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

注册控制器

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

omn??iauth回调控制器

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,:google_oauth2].each do |provider|
    provides_callback_for provider
  end



end

用户/完成注册视图

<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,placeholder: 'Last name (surname)' %>
            <p class="help-block">Add your last name</p>
        <% end %>    


        <% if !current_user.email_verified? %> 
          <%= f.text_field :email,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>

用户/身份验证视图

<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,: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>

路线

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.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"

我有这个工作,所以用户只能使用一种方法进行身份验证.我不知道如何让这个工作.我已经尝试了所有可以找到的资源来解决这个问题,但我陷入困境.

我将这一切都与每个社交插件和电子邮件一起使用,但我没有的是能够向现有用户添加身份(在当前会话中),以便下次登录时他们可以使用任何可接受的身份.

有人可以帮忙吗?

解决方法

由于无法查看所有代码,我只创建了一个与多个提供程序一起运行的shell应用程序.我只是按照你在 sourcey提到的教程中的步骤进行操作.这是我 repo的链接.

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

如果您想让用户选择添加他们自己的omniauth帐户(身份),而不是通过应用程序授权自动完成,您只需为用户输入一个表单输入数字uid并在控制器中创建自己的身份或者这样的后端:

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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读