2015-11-03 231 views
11

我想(再次)使用Rails 4,devise和omniauth設置身份驗證。Rails,Devise&Omniauth - 設置問題

我試圖按照這篇文章的例子:Rails 4, Devise, Omniauth (with multiple providers)

我已經安裝了這些寶石:

gem 'devise' 
gem 'omniauth-google-oauth2' 
gem 'omniauth-facebook' 
gem 'omniauth-twitter' 
gem 'omniauth-linkedin-oauth2' 
gem 'oauth2' 

我有一個用戶模型,以及模型認證。

我:

User.rb:

has_many :authentications 

def disapprove 
    self.approved = false 
    end 

    def approve 
    self.approved = true 
    end 

社交= { Facebook的:「Facebook的, google_oauth2: '谷歌', LinkedIn: 'LinkedIn' }

def self.from_omniauth(auth, current_user) 
    authentication = Authentication.where(:provider => auth.provider, 
            :uid => auth.uid.to_s, 
            :token => auth.credentials.token, 
            :secret => auth.credentials.secret).first_or_initialize 
    authentication.profile_page = auth.info.urls.first.last unless authentication.persisted? 
    if authentication.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 
    authentication.user = user 
    authentication.save 
    end 
    authentication.user 
end 

def fetch_details(auth) 
    self.first_name = auth.info.first_name 
    self.last_name = auth.info.last_name 
    self.email = auth.info.email 
    self.image = URI.parse(auth.info.image) 
end 

Authentication.rb

belongs_to :user 

的routes.rb

devise_for :users, 
      :controllers => { 
:registrations => "users/registrations", 


      :omniauth_callbacks => 'users/omniauth_callbacks', 
      } 

用戶/ registrations_controller

class Users::RegistrationsController < Devise::RegistrationsController 
    #before_filter :check_permissions , :only => [ :new, :create, :cancel ] 
    #skip_before_filter :require_no_authentication 

    def check_permissions 
    authorize! :create, resource 
    end 

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

    def create 
     @user = User.new(user_params) #(params[:user]) 

     respond_to do |format| 
      if resource.save 
      # Tell the UserMailer to send a welcome email after save 
      # {@user.send_admin_mail 
      # @user.send_user_welcome_mail} 

      format.html { redirect_to(profile_path(@user.profile))} 
      #, notice: 'We have received your registration. We will be in touch shortly.') } 
      #format.json { render json: root_path, status: :created, location: @user } 
      else 
      #format.html { redirect_to(root_path, alert: 'Sorry! There was a problem with your registration. Please contact us to sort it out.') } 
      format.html { render action: 'new' } 
      format.json { render json: @user.errors, status: :unprocessable_entity } 
      end 
     end 
     end 

     private 
     def user_params 
      params.require(:user).permit(:first_name, :last_name, :email, :password) 
     end 



     # protected 
     # def after_sign_up_path_for(resource) 
     #  'subscribers/new' 
     # end 
end 

用戶/ Omniauth_callbacks控制器

類用戶:: OmniauthCallbacksController <設計:: OmniauthCallbacksController

# try again following https://stackoverflow.com/questions/21249749/rails-4-devise-omniauth-with-multiple-providers 

    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 profile_path(@user.profile) 
     else 
     redirect_to root_path 
     end 
    else 
     session['devise.user_attributes'] = user.attributes 
     redirect_to root_path 
    end 
    end 

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

的色器件/新註冊的觀點說:

<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> 

    <div class="row"> 
     <div class="col-md-3 col-md-offset-3"> 
      <div class="row"> 
       <div class="col-md-12"> 

        <%- if devise_mapping.omniauthable? %> 
          <div class="facebookauth"> 
          <%= link_to "Join with Facebook", user_omniauth_authorize_path(:facebook) %> 
          </div> 
        <% end -%> 

       </div> 
       </div> 


      <div class="row"> 
      <div class="col-md-12"> 

       <%- if devise_mapping.omniauthable? %> 
        <div class="googleauth"> 
        <%= link_to "Join with Google", user_omniauth_authorize_path(:google_oauth2) %> 
        </div> 
       <% end -%> 
      </div> 
      </div> 



     <div class="row"> 
       <div class="col-md-12"> 

        <%- if devise_mapping.omniauthable? %> 
         <div class="linkedinauth"> 
         <%= link_to "Join with LinkedIn", user_omniauth_authorize_path(:linkedin) %> 
         </div> 
        <% end -%> 
       </div> 
     </div> 

      <div class="row"> 
      <div class="col-md-12"> 

       <%- if devise_mapping.omniauthable? %> 
        <div class="twitterauth"> 
        <%= link_to "Join with Twitter", user_omniauth_authorize_path(:twitter) %> 
        </div> 
       <% end -%> 

      </div> 
      </div> 

     </div> 

     <div class="col-md-5"> 
      <div class="emailform"> 
      <div class="form-inputs", style="margin-left: 7%"> 


        <%= devise_error_messages! %> 
        <%= f.input :first_name, :label_html => {:class => 'deviselabels'}, autofocus: true, required: false, :input_html => {:maxlength => 15, :size => 40, class: 'lineitemdevise'} %> 
        <%= f.input :last_name, :label_html => {:class => 'deviselabels'}, required: false, :input_html => {:maxlength => 15, :size => 40, class: 'lineitemdevise'} %> 
        <%= f.input :email, :label_html => {:class => 'deviselabels'}, required: false, autofocus: false, placeholder: "Please use your work or university address", :input_html => {:maxlength => 55, :size => 40, class: 'lineitemdevise'} %> 
        <%= f.input :password, :label_html => {:class => 'deviselabels'}, required: false, placeholder: "Minimum 8 characters", :input_html => {:maxlength => 15, :size => 40, class: 'lineitemdevise'} %> 
       </div> 

      <div class="form-actions"> 
      <%= f.button :submit, "Join by email", :class => "dcpb" %> 
     </div> 
      <% end %> 
      </div> 
     </div> 

我有一個名爲profile.rb另一種模式。

profile belongs_to user 

問題:

  1. 這一切都不工作。當我點擊每個社交媒體登錄鏈接時,頁面就會跳轉到通過電子郵件形式註冊。

Heroku的記錄錯誤消息指出:

(facebook) Authentication failure! invalid_credentials: OAuth2::Error, : 
2015-11-03T07:05:48.237549+00:00 app[web.1]: {"error":{"message":"Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request","type":"OAuthException","code":100,"fbtrace_id":"HD3mnzmSTEw"}} 
  • 當我與電子郵件和密碼完成註冊通過電子郵件形式,用戶名被識別(在導航欄說你好,但是當我進入軌道控制檯,用戶沒有列出。
  • 此外,當我點擊用戶名,我得到它說,配置文件不存在的錯誤。Heroku的日誌說:

    (Couldn't find Profile with 'id'=3) 
    
  • 有沒有讓社交媒體註冊工作,以創建一個新用戶需要另一步?
  • 我的一次新的嘗試:

    我已經改變了上述所有的,並試圖再次,在Railscasts視頻的方法如下。

    我現在使用用戶模型和身份驗證模型。

    在user.rb,我有:

    has_many :authentications, :dependent => :delete_all 
    
    def apply_omniauth(omniauth) 
         authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => auth['credentials']['token']) 
    
    end 
    

    authentication.rb

    belongs_to :user 
    
    def self.from_omniauth(auth) 
        where(auth.slice(:provider, :uid)).first_or_create do | user | 
         authentication.provider = auth.provider 
         authentication.uid = auth.uid 
         authentication.user.first_name = auth.first_name 
         authentication.user.last_name = auth.last_name 
         authentication.user.image = auth.info.image 
    
        end 
        end 
    

    Authentications_controller:

    class AuthenticationsController < ApplicationController 
        before_action :set_authentication, only: [:destroy] 
    
        def index 
        @authentications = current_user.authentications if current_user 
        end 
    
    
        def create 
        omniauth = request.env["omniauth.auth"] 
        authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid']) 
        if authentication 
         sign_in_and_redirect_user(:user, authentication.user.profile) 
    
        elsif current_user 
         current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid']) 
         redirect_to user.profile_url 
        else 
         user = User.new 
         user.omniauth(omniauth) 
         if user.save! 
         sign_in_and_redirect_user(:user, user.profile) 
         else 
         session[:omniauth] = omniauth.except('extra') 
         redirect_to new_user_registration_url 
         end 
        end 
        end 
    
        def destroy 
        @authentication.destroy 
        respond_to do |format| 
         format.html { redirect_to authentications_url } 
         format.json { head :no_content } 
        end 
        end 
    
        private 
        # Use callbacks to share common setup or constraints between actions. 
        def set_authentication 
         @authentication = current_user.authentications.find(params[:id]) 
        end 
    end 
    

    在routes.rb中,我有:

    devise_for :users, 
          :controllers => { 
           :registrations => "users/registrations", 
          } 
    patch '/auth/:provider/callback' => 'authentications#create' 
    

    Omniauth.rb

    需要 'omniauth Facebook的' 需要 'omniauth,谷歌-的oauth2'

    OmniAuth.config.logger = Rails.logger

    Rails.application.config.middleware.use OmniAuth::Builder do 
        provider :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_KEY'], 
        :scope => 'public_profile', info_fields: 'id,first_name,last_name,link,email', 
        :display => 'popup', 
        :client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}} 
    

    後來,當我嘗試這,我得到這個錯誤:

    (facebook) Authentication failure! invalid_credentials: OAuth2::Error, : 
    2015-11-05T06:4839+00:00 app[web.1]: {"error":{"message":"Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request","type":"OAuthException","code":100,"fbtrace_id":"CrvXN22Z"}} 
    

    我找到錯誤消息奇的下一個部分,因爲它是指通話後退控制器,我不再使用(整個事情被註釋掉,沒有路線)。

    Authentication failure! invalid_credentials: OAuth2::Error, : 
    2015-11-05T08:24:16.010951+00:00 app[web.1]: Processing by Devise::OmniauthCallbacksController#failure as HTML 
    2015-11-05T08:24:16.012648+00:00 app[web.1]: Redirected to http://www.dder.com/users/sign_in 
    

    進一步企圖

    我一直在試圖建立現在omniauth超過1.5年設計。這是我最近的嘗試(在sitepoint.com/rails-authentication-oauth-2-0-omniauth上的Sitepoint教程之後)。我之前嘗試過使用本教程,但沒有取得任何成功,所以我做了一些調整,嘗試將其應用於有關此主題的其他教程的某些方面。

    我現在有:

    user.rb

    has_many :authentications, :dependent => :delete_all 
    
    def apply_omniauth(omniauth) 
         authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => auth['credentials']['token']) 
    
        end 
    

    認證。RB

    belongs_to :user 
        def self.from_omniauth(auth) 
        where(auth.slice(:provider, :uid)).first_or_create do | user | 
         authentication.provider = auth.provider 
         authentication.uid = auth.uid 
         authentication.user.first_name = auth.first_name 
         authentication.user.last_name = auth.last_name 
         authentication.user.image = auth.info.image 
    
        end 
        end 
    

    認證控制器

    class AuthenticationsController < Devise::OmniauthCallbacksController 
         before_action :set_authentication, only: [:destroy] 
    
         def index 
         @authentications = current_user.authentications if current_user 
         end 
    
    
         def create 
         omniauth = request.env["omniauth.auth"] 
         authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid']) 
         if authentication 
          sign_in_and_redirect_user(:user, authentication.user.profile) 
    
         elsif current_user 
          current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid']) 
          redirect_to user.profile_url 
         else 
          user = User.new 
          user.omniauth(omniauth) 
          if user.save! 
          sign_in_and_redirect_user(:user, user.profile) 
          else 
          session[:omniauth] = omniauth.except('extra') 
          redirect_to new_user_registration_url 
          end 
         end 
         end 
    
         def destroy 
         @authentication.destroy 
         respond_to do |format| 
          format.html { redirect_to authentications_url } 
          format.json { head :no_content } 
         end 
         end 
    
         private 
         # Use callbacks to share common setup or constraints between actions. 
         def set_authentication 
          @authentication = current_user.authentications.find(params[:id]) 
         end 
        end 
    

    註冊控制器

    class Users::RegistrationsController < Devise::RegistrationsController 
        #before_filter :check_permissions , :only => [ :new, :create, :cancel ] 
        #skip_before_filter :require_no_authentication 
        # before_action :configure_permitted_parameters, if: :devise_controller? # Suggestion from Sitepoint tutorial - not currently implemented because not sure about the difference between this and set params. 
    
        def check_permissions 
        authorize! :create, resource 
        end 
    
        def index 
        if params[:approved] == "false" 
         @users = User.find_all_by_approved(false) 
        else 
         @users = User.all 
        end 
        end 
    
        def create 
        super 
        session[:omniauth] = nil unless @user.new_record? 
        end 
    
        # THIS IS A SUGGESTION FROM SITEPOINT TUTORIAL 
        # protected 
    
        # def configure_permitted_parameters 
        #  devise_parameter_sanitizer.for(:sign_up) << [:first_name, :last_name] 
        # end 
    
    
        private 
        def user_params 
          params.require(:user).permit(:first_name, :last_name, :email, :password) 
        end 
    
        def build_resource(*args) 
         super 
         if session[:omniauth] 
         @user.apply_omniauth(session[:omniauth]) 
         @user.valid? 
         end 
        end 
    
    end 
    

    路線

    ​​050720

    我可以檢查這些路線:

    rake routes | grep auth 
             user_omniauth_authorize GET|POST /users/auth/:provider(.:format)                 authentications#passthru {:provider=>/facebook|linkedin|twitter|google_oauth2/} 
             user_omniauth_callback GET|POST /users/auth/:action/callback(.:format)               authentications#:action 
                   GET  /auth/:provider/callback(.:format)                authentications#create 
    

    新登記的觀點

    <%- if devise_mapping.omniauthable? %> 
            <div class="twitterauth"> 
            <%= link_to "Join with Twitter", user_omniauth_authorize_path(:twitter) %> 
            </div> 
           <% end -%> 
    

    部分我真的不知道這條道路是從哪裏來的。不知道它爲什麼被命名。

    新的會話視圖部分

    <%- if devise_mapping.omniauthable? %> 
            <div class="twitterauth"> 
            <%= link_to "Login with Twitter", user_omniauth_authorize_path(:twitter) %> 
            </div> 
           <% end -%> 
    

    當前出錯:

    AbstractController::ActionNotFound at /users/auth/twitter/callback 
    
    The action 'twitter' could not be found for AuthenticationsController 
    
    +0

    您是否設置了環境變量ENV [ 'FACEBOOK_ID'],ENV [ 'FACEBOOK_KEY']在Heroku? – apod

    +0

    是的 - 它們在Heroku中正確配置 – Mel

    +0

    Oauth 2.01有一個特定的問題。您需要在設備oauth:config中指定一個回調URL。 config.omniauth:臉譜,「APP_ID」,「APP_SECRET」,callback_url:「CALLBACK_URL」。如果這不起作用,你是否檢查了Facebook中的憑據和應用程序設置?你的域名需要與你的本地環境完全相同? – bulleric

    回答

    0

    有一個名爲dom的寶石,有人專門與多個供應商來管理設計。它使事情變得簡單!

    另外,我認爲你應該閱讀這些文章。我敢肯定,你可以解決你所有的問題與他們:

    1. Devise OmniAuth: Overview
    2. OmniAuth Managing multiple provaders
    +0

    嗨阿方索,感謝您的建議。我經常諮詢寶石文檔。經過至少200次嘗試(您可以在這張板上看到至少40條與這些文章相關的其他問題),我找到了教程並試圖遵循這些問題。這個問題與教程有關。 – Mel

    相關問題