2013-07-26 2 views
1

Я использую omniauth-facebook камень с завещанию для аутентификации с Facebook в моем приложении рельсов в моей модели пользователясоединиться с Facebook для существующих пользователей

def self.from_omniauth(auth) 
    # immediately get 60 day auth token 
    oauth = Koala::Facebook::OAuth.new("App Key", "App secrets") 
    new_access_info = oauth.exchange_access_token_info auth.credentials.token 
    new_access_token = new_access_info["access_token"] 
    new_access_expires_at = DateTime.now + new_access_info["expires"].to_i.seconds 
    begin 
    where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user| 
     user.provider = auth.provider 
     user.uid = auth.uid 
     user.username = auth.info.first_name 
     user.lastname =auth.info.last_name 
     user.email =auth.info.email 
     user.authentication_token = new_access_token 
     user.oauth_expires_at = new_access_expires_at 
     user.save! 
    end 
    rescue ActiveRecord::RecordInvalid 
    end 
end 

#interact with facebook 
def facebook 
    @facebook ||= Koala::Facebook::API.new(authentication_token) 
    block_given? ? yield(@facebook) : @facebook 
rescue Koala::Facebook::APIError => e 
    logger.info e.to_s 
    nil # or consider a custom null object 
end 


def self.new_with_session(params, session) 
    if session["devise.user_attributes"] 
    new(session["devise.user_attributes"], :without_protection=> true) do |user| 
     user.attributes = params 
     user.valid? 
    end 
    else 
    super 
    end 
end 

и на моем omniauth_callbacks контроллера у меня есть этот метод:

def all 
    user = User.from_omniauth(request.env["omniauth.auth"]) 
    if user.persisted? 
    flash.notice = "Signed in!" 
    sign_in_and_redirect user 
    else 
    session["devise.user_attributes"] = user.attributes 
    redirect_to new_user_registration_url 
    end 
end 
alias_method :facebook, :all 

Эти методы используются для аутентификации пользователя с нуля через Facebook. Мне нужен способ подключения существующих пользователей с их счета Facebook не новыми, если они зарегистрированы с помощью метода регистрации нормальный DEViSE

Когда существующий пользователь пытается войти в систему с помощью Facebook следующее сообщение об ошибке:

A `NoMethodError` occurred in `omniauth_callbacks#facebook`: 

undefined method `persisted?' for nil:NilClass 
app/controllers/omniauth_callbacks_controller.rb:4:in `all' 
+0

ru предоставление fbid и секретного ключа для authoauth = Koala :: Facebook :: OAuth.new (ENV [ FACEBOOK_APP_ID "], ENV [" FACEBOOK_SECRET "]) – Debadatt

+0

ru gett правильный ответ в oauth? означает, что после печати oauth являются правильными значениями? – Debadatt

+0

да, вопрос: я хочу, чтобы аутентифицировать существующих пользователей в моем приложении со своими учетными записями facebook. –

ответ

4

Сначала вы можете найти пользователя по email и просто обновить provider и uid поля в случае, если он уже существует.

Таким образом, ваш User.from_omniauth может, выглядит следующим образом:

def self.from_omniauth(auth) 
    # immediately get 60 day auth token 
    oauth = Koala::Facebook::OAuth.new("", "") 
    new_access_info = oauth.exchange_access_token_info auth.credentials.token 
    new_access_token = new_access_info["access_token"] 
    new_access_expires_at = DateTime.now + new_access_info["expires"].to_i.seconds 

    user = where(provider: auth.provider, uid: auth.uid).first 
    unless user 
    # in that case you will find existing user doesn't connected to facebook 
    # or create new one by email 
    user = where(email: auth.info.email).first_or_initialize 
    user.provider = auth.provider # and connect him to facebook here 
    user.uid = auth.uid   # and here 
    user.username = auth.info.first_name 
    user.lastname = auth.info.last_name 
    user.authentication_token = new_access_token 
    user.oauth_expires_at = new_access_expires_at 
    # other user's data you want to update 
    user.save! 
    end 

    user 
end 

обн:

В случае, если вы столкнулись ошибки проверки пароля вы можете переопределить User#password_required? метод, чтобы пропустить проверку для пользователя вход через Facebook.

Это поведение, описанное в следующем episode из Railscasts

+0

его работает для подключения существующего пользователя .. но когда новый пользователь попытался зарегистрироваться в facebook. ActiveRecord :: RecordInvalid произошел в omniauth_callbacks # facebook: поднято –

+0

Возможно, вы пропустили некоторые обязательные поля. Попробуйте использовать 'binding.pry' для проверки ошибок проверки или' user.valid ?; Rails.logger.info user.errors.messages', чтобы проверить ошибки проверки. – ck3g

+0

проблема главным образом на поле электронной почты –

0

Вы можете иметь ваш from_omniauth быть что-то вроде этого:

def self.from_omniauth(auth) 
    where(auth.info.slice(:email)).first_or_create do |user| 
     user.email = auth.info.email 
     user.password = Devise.friendly_token[0,20] 
     user.username = auth.info.name 
     user.description = auth.extra.raw_info.bio 
    end 
end 

Таким образом, если есть существующий пользователь с электронной почтой такой же, как facebook счета, то first_or_create вернет его, а затем пользователь сможет выполнить вход (это не будет обновление).

+0

Прости, простите об этом. Таким образом, 'uid' и' provider' никогда не будут установлены. И если FB позволяет пользователям редактировать свою электронную почту без подтверждения, они могут изменить свой адрес электронной почты и войти в учетные записи других пользователей. –

1

Просто для добавления обновленной версии ответа на рельсы 4 и изобрести 3.4.x

Как это, как обновленный OmniAuth будет выглядеть

def self.from_omniauth(auth) 
    if !where(email: auth.info.email).empty? 
     user = where(email: auth.info.email).first 
     user.provider = auth.provider # and connect him to facebook here 
     user.uid = auth.uid   # and here 
     user.save! 
     user 
    else 
     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.first_name = auth.info.name # assuming the user model has a name 
     user.avatar = process_uri(auth.info.image) # assuming the user model has an image 
     end 
    end 
    end 

Просто найдите пользователь по электронной почте, если есть один, просто добавьте провайдера и uid, если его нет, просто создайте его, как предложено в documentation

+0

Это лучший ответ! –

Смежные вопросы