ruby-on-rails – Rails 4 – 设计Omniauth并允许单个用户通过多
我正在尝试用Rails 4创建一个应用程序.
我一直在尝试(3年)弄清楚如何使Devise和Omniauth工作,以便用户可以在他们的用户配置文件中添加多个社交媒体帐户. 我已经阅读了所有的设计和omniauth文档.我可以使用这些文档获得的最佳效果是添加1个单独的社交媒体帐户.那不是我想要的. 我试过这个网站点教程 我试过这个willschenck教程 我试过这个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并自己输入. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |