簡體   English   中英

OmniAuth Oauth2無法將Instagram用戶帳戶持久化為用戶模型(Devise)

[英]OmniAuth Oauth2 not persisting Instagram user account to User model (Devise)

我正在使用與Devise gem搭配使用的Omniauth gem進行用戶身份驗證(這是一個Wiki 。我在我的應用中選擇了Oauth2策略來對Instagram用戶進行身份驗證。

我的問題是,通過Instagram身份驗證登錄的用戶未保留到我的用戶模型中。 . 在通過Instagram進行身份驗證之后,它們將被重定向到新的用戶注冊路徑

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def instagram
    # You need to implement the method below in your model (e.g. app/models/user.rb)
    @user = User.from_omniauth(request.env["omniauth.auth"])
    if @user.persisted?

      sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
      set_flash_message(:notice, :success, :kind => "Instagram") if is_navigational_format?
    else
      session["devise.instagram_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end
end

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  devise :omniauthable, :omniauth_providers => [:instagram]

  def self.from_omniauth(auth)
  where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
    user.email = auth.info.email
    user.password = Devise.friendly_token[0,20]
    # user.name = auth.info.name   # assuming the user model has a name
    # user.image = auth.info.image # assuming the user model has an image
  end
end

def self.new_with_session(params, session)
    super.tap do |user|
      if data = session["devise.instagram_data"] && session["devise.instagram_data"]["extra"]["raw_info"]
        user.email = data["email"] if user.email.blank?
      end
    end
end

end

Users表具有適當的列( provideruid

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "provider"
    t.string   "uid"
  end

最后,這是通過Instagram身份驗證登錄時的輸出

Started GET "/users/auth/instagram" for ::1 at 2015-09-25 09:57:54 -0400
I, [2015-09-25T09:57:54.577637 #7451]  INFO -- omniauth: (instagram) Request phase initiated.


Started GET "/users/auth/instagram" for ::1 at 2015-09-25 09:57:54 -0400
I, [2015-09-25T09:57:54.655615 #7451]  INFO -- omniauth: (instagram) Request phase initiated.


Started GET "/users/auth/instagram/callback?code=SOME_CODE&state=SOME_STATE" for ::1 at 2015-09-25 09:57:54 -0400
I, [2015-09-25T09:57:54.811861 #7451]  INFO -- omniauth: (instagram) Callback phase initiated.
Processing by Users::OmniauthCallbacksController#instagram as HTML
  Parameters: {"code"=>"SOME_CODE", "state"=>"SOME_STATE"}
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."provider" = ? AND "users"."uid" = ?  ORDER BY "users"."id" ASC LIMIT 1  [["provider", "instagram"], ["uid", "343664764"]]
   (0.1ms)  begin transaction
   (0.1ms)  rollback transaction
Redirected to http://localhost:3000/users/sign_up

在深入研究代碼之后,添加了調試器斷點以跟蹤從視圖到控制器再到控制器再到控制器的數據流,我意識到我的問題是Instagram API不提供特定用戶的電子郵件。 由於Devise在默認情況下需要一封電子郵件,並且我為電子郵件user.email = auth.info.email分配了一個空白值,因此保存從未完成,因此我將被重定向到新的用戶注冊路徑new_user_registration_url

我如何調試

首先,我需要一條錯誤消息才能真正了解問題所在。 所以,我加了一個“!” save!save! from_omniauth類方法中。

def self.from_omniauth(auth)
  where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
    user.email = auth.info.email
    user.password = Devise.friendly_token[0,20]
    user.save! 
  end
end

save! ,驗證總是運行,如果我失敗了,則會引發ActiveRecord :: ActiveRecordError 錯誤消息然后指出,電子郵件字段不能為空。

所以現在我實際上有更多的信息可以使用。 我的解決方法不是很好,我也不會提出建議-但這解決了問題。

解決方法

我的解決方案是為每個通過Instagram注冊的用戶創建一個虛擬電子郵件。 在我的from_omniauth方法中,我將用戶電子郵件字段分配給nickname (從instagram身份驗證返回)字段和通用“ @ example.com”的串聯:

user.email = auth.info.nickname + "@example.com"

這不是一個可持續的解決方案,因為對於使用Instagram注冊的每個人,您最終將收到錯誤的電子郵件(忘記通過Action Mailer向他們發送電子郵件)。

我尚未實現(但將要實現)的一個更好的解決方案是將通過Instagram注冊/登錄的用戶重定向到特定的URL,您將在該URL中提示用戶輸入其電子郵件地址。 然后,您可以將該信息發送回去,以便可以由控制器處理並正確保存。

當然,這是用戶可能不願意采取的額外步驟,但是電子郵件地址是一項寶貴的資產,可以用來做許多事情,例如新聞通訊和其他促銷電子郵件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM