Facebook login integration with omniauth on rails

I am using Railscast Episode # 250 to implement authentication from scratch. However, now I want to implement Facebook login. From googling, I found that OmniAuth and Devise are the main contenders for this in Rails

However, this example page confuses me: https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

It states:

With Rails 3.0.3 use this in your Gemfile, instead, if the rails have a problem loading the oauth kernel:

gem "omniauth"

Then you need to declare the provider in your config / Initializers / devise.rb:

config.omniauth: facebook, "APP_ID", "APP_SECRET"

Question

Are omniauth and are being developed interelated?

What to do to implement a Facebook account in my Railscast 250 authentication

+6
source share
2 answers

In your particular case, you may think that Devise allows your application to authenticate users using a form (for example, using email and password) or an authentication token, Omniauth allows your application to "talk" with Facebook servers for user authentication. In other words, Omniauth sits on top of Devise and expands the number of authentication methods for your user.

To sign in to Facebook, you need to:

0) configure devise: just follow the below: https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

1) show the link in your view that when clicked by the user, it will inform that Omniauth will start β€œtalking” on the Facebook server.

=link_to image_tag("facebook_64.png", :size => "64x64", :alt => "Facebook"), user_omniauth_authorize_path(:facebook, :display=>"dialog"), :title=>"Facebook" 

2) At some point, the Facebook server will call your application, so you will need to implement a controller to respond to Facebook

 class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController before_filter { @omniauth_hash = env["omniauth.auth"] } # This method is responsible to create a registration_hash given an # omniaauth_hash # schama: https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema def self.build_registration_hash(omniauth_hash={}) if (omniauth_hash["provider"].downcase.eql?("facebook")) provider = "facebook" # catch any excpetions thrown by code just to make sure we can continue even if parts of the omnia_has are missing begin first_name = omniauth_hash['user_info']['first_name'] last_name = omniauth_hash['user_info']['last_name'] sex = omniauth_hash.fetch('extra', {}).fetch('user_hash',{})['gender'] birthday = Date.strptime(omniauth_hash.fetch('extra', {}).fetch('user_hash', {})['birthday'],'%m/%d/%Y') if omniauth_hash.fetch('extra', {}).fetch('user_hash', {})['birthday'] if omniauth_hash.fetch('extra', {}).fetch('user_hash', {})['timezone'] utc_offset_in_hours = (omniauth_hash.fetch('extra', {}).fetch('user_hash', {})['timezone']).to_i time_zone = (ActiveSupport::TimeZone[utc_offset_in_hours]).name else time_zone = nil end locale = omniauth_hash.fetch('extra', {}).fetch('user_hash', {})['locale'] home_town = omniauth_hash.fetch('extra', {}).fetch('user_hash', {}).fetch('location', {})['name'] if omniauth_hash.fetch('user_info', {})['image'] photo_url = (omniauth_hash.fetch('user_info', {})['image']).gsub("=square","=large") #http://graph.facebook.com/531564247/picture?type=square else photo_url = nil end rescue => ex logger.error("Error while parsing facebook auth hash: #{ex.class}: #{ex.message}") sex = nil birthday = nil time_zone = nil locale = nil home_town = nil photo_url = nil end elsif omniauth_hash['uid'].downcase.include?("google.com") provider = "google" if omniauth_hash['user_info']['first_name'] and omniauth_hash['user_info']['last_name'] first_name = omniauth_hash['user_info']['first_name'] last_name = omniauth_hash['user_info']['last_name'] elsif omniauth_hash['user_info']['name'] first_name = omniauth_hash['user_info']['name'].split(' ')[0] last_name = omniauth_hash['user_info']['name'].split(' ')[1] else first_name = nil last_name = nil end sex = nil birthday = nil time_zone = nil locale = nil home_town = nil photo_url = nil elsif omniauth_hash['uid'].downcase.include?("yahoo.com") provider = "yahoo" if omniauth_hash['user_info']['first_name'] and omniauth_hash['user_info']['last_name'] first_name = omniauth_hash['user_info']['first_name'] last_name = omniauth_hash['user_info']['last_name'] elsif omniauth_hash['user_info']['name'] first_name = omniauth_hash['user_info']['name'].split(' ')[0] last_name = omniauth_hash['user_info']['name'].split(' ')[1] else first_name = nil last_name = nil end sex = nil birthday = nil time_zone = nil locale = nil home_town = nil photo_url = nil elsif omniauth_hash['uid'].downcase.include?("aol.com") if omniauth_hash['user_info']['first_name'] and omniauth_hash['user_info']['last_name'] first_name = omniauth_hash['user_info']['first_name'] last_name = omniauth_hash['user_info']['last_name'] elsif omniauth_hash['user_info']['name'] first_name = omniauth_hash['user_info']['name'].split(' ')[0] last_name = omniauth_hash['user_info']['name'].split(' ')[1] else first_name = nil last_name = nil end provider = "aol" sex = nil birthday = nil time_zone = nil locale = nil home_town = nil photo_url = nil else provider = "open_id" if omniauth_hash['user_info']['first_name'] and omniauth_hash['user_info']['last_name'] first_name = omniauth_hash['user_info']['first_name'] last_name = omniauth_hash['user_info']['last_name'] elsif omniauth_hash['user_info']['name'] first_name = omniauth_hash['user_info']['name'].split(' ')[0] last_name = omniauth_hash['user_info']['name'].split(' ')[1] else first_name = nil last_name = nil end sex = nil birthday = nil time_zone = nil locale = nil home_town = nil photo_url = nil end h = { :provider => provider, :email => omniauth_hash['user_info']['email'], :profile_attributes => { :first_name => first_name , :last_name => last_name, :avatar_url => photo_url, :sex => sex, :birthday => birthday, :time_zone => time_zone, :locale => locale, :location => home_town } } end def process_callback # The registration hash isolates the rest of the code from learning all the different structures # of the omnia_hash registration_hash = Users::OmniauthCallbacksController.build_registration_hash(@omniauth_hash) logger.debug(registration_hash.to_yaml) # Set the @user to nil @user = nil # Find if an authentication token for this provider and user id already exists authentication = Authentication.find_by_provider_and_uid(@omniauth_hash['provider'], @omniauth_hash['uid']) if authentication # We found an authentication if user_signed_in? && (authentication.user.id != current_user.id) flash[:error] = I18n.t "controllers.omniauth_callbacks.process_callback.error.account_already_taken", :provider => registration_hash[:provider].capitalize, :account => registration_hash[:email] redirect_to edit_user_account_path(current_user) return end else # We could not find the authentication than create one authentication = Authentication.new(:provider => @omniauth_hash['provider'], :uid => @omniauth_hash['uid']) if user_signed_in? authentication.user = current_user else registration_hash[:skip_confirmation] = true authentication.user = User.find_by_email(registration_hash[:email]) || User.create_user(registration_hash) end end @user = authentication.user # save the authentication authentication.token = @omniauth_hash authentication.provider_name = registration_hash[:provider] authentication.provider_username = registration_hash[:email] if !authentication.save logger.error(authentication.errors) end # If a user is signed in then he is trying to link a new account if user_signed_in? if authentication.persisted? # This was a linking operation so send back the user to the account edit page flash[:success] = I18n.t "controllers.omniauth_callbacks.process_callback.success.link_account", :provider => registration_hash[:provider].capitalize, :account => registration_hash[:email] else flash[:error] = I18n.t "controllers.omniauth_callbacks.process_callback.error.link_account", :provider => registration_hash[:provider].capitalize, :account => registration_hash[:email], :errors =>authentication.errors end redirect_to edit_user_account_path(current_user) else # This was a sign in operation so sign in the user and redirect it to his home page if @user.persisted? && authentication.persisted? flash[:success] = I18n.t "controllers.omniauth_callbacks.process_callback.success.sign_in", :provider => registration_hash[:provider].capitalize, :account => registration_hash[:email] sign_in_and_redirect(:user,@user) else session['registration_hash'] = registration_hash flash[:error] = I18n.t "controllers.omniauth_callbacks.process_callback.error.sign_in", :provider => registration_hash[:provider].capitalize, :account => registration_hash[:email] redirect_to new_registration_users_url end end end def facebook process_callback end def gmail process_callback end 

Now you will notice that I call User.create_user (registration_hash). The implementation of this method will depend on how your application creates the user, but at least the method should create the user and assign him a random password:

 def self.create_user(registration_hash) logger.info "Creating new user with registration hash: #{registration_hash.to_yaml}" unless registration_hash or resigration_hash.empty? return nil end user = User.new user.email = registration_hash[:email] if registration_hash[:password] user.password = registration_hash[:password] else user.password = Devise.friendly_token[0,20] end user.password_confirmation = user.password # custom app code here... if registration_hash[:skip_confirmation] == true user.confirm! end user end 

Note. My application supports login with another service, so I implemented a table containing authentication tokens.

Hope this helps you get started.

+8
source

Source: https://habr.com/ru/post/896982/


All Articles