Created
September 23, 2012 07:07
-
-
Save stefanobernardi/3769177 to your computer and use it in GitHub Desktop.
Multiple omniauth providers and omniauth-identity on the main user model
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ApplicationController < ActionController::Base | |
protect_from_forgery | |
protected | |
def current_user | |
@current_user ||= User.find_by_id(session[:user_id]) | |
end | |
def signed_in? | |
!!current_user | |
end | |
helper_method :current_user, :signed_in? | |
def current_user=(user) | |
@current_user = user | |
session[:user_id] = user.nil? ? user : user.id | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# == Schema Information | |
# | |
# Table name: authentications | |
# | |
# id :integer not null, primary key | |
# user_id :integer | |
# provider :string(255) | |
# uid :string(255) | |
# created_at :datetime not null | |
# updated_at :datetime not null | |
# | |
class Authentication < ActiveRecord::Base | |
attr_accessible :provider, :uid, :user_id | |
belongs_to :user | |
def self.find_with_omniauth(auth) | |
find_by_provider_and_uid(auth['provider'], auth['uid']) | |
end | |
def self.create_with_omniauth(auth) | |
create(uid: auth['uid'], provider: auth['provider']) # and other data you might want from the auth hash | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%= simple_form_for @user, :url => '/auth/identity/register' do |f| %> | |
<%= @user.inspect %> | |
<h1>Create an Account</h1> | |
<%# specify :input_html to avoid params nesting %> | |
<%= f.input :name, :input_html => {:name => 'name'} %> | |
<%= f.input :email, :input_html => {:name => 'email'} %> | |
<%= f.input :password, :as => 'password', :input_html => {:name => 'password'} %> | |
<%= f.input :password_confirmation, :label => "Confirm Password", :as => 'password', :input_html => {:name => 'password_confirmation'} %> | |
<button type='submit'>Sign Up</button> | |
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Rails.application.config.middleware.use OmniAuth::Builder do | |
provider :identity, fields: [:email, :name], model: User, on_failed_registration: lambda { |env| | |
UsersController.action(:new).call(env) | |
} | |
provider :abc | |
provider :def | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AppName::Application.routes.draw do | |
match '/auth/:provider/callback', to: 'sessions#create' #omniauth route | |
match '/signup', to: 'users#new' | |
match '/login', to: 'sessions#new' | |
match '/logout', to: 'sessions#destroy' | |
resources :users #needed by omniauth-identity | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SessionsController < ApplicationController | |
def new | |
# Stuff to display on the login-page. | |
end | |
def create | |
auth = request.env['omniauth.auth'] | |
# Find an authentication or create an authentication | |
@authentication = Authentication.find_with_omniauth(auth) | |
if @authentication.nil? | |
# If no authentication was found, create a brand new one here | |
@authentication = Authentication.create_with_omniauth(auth) | |
end | |
if signed_in? | |
if @authentication.user == current_user | |
# User is signed in so they are trying to link an authentication with their | |
# account. But we found the authentication and the user associated with it | |
# is the current user. So the authentication is already associated with | |
# this user. So let's display an error message. | |
redirect_to root_path, notice: "You have already linked this account" | |
else | |
# The authentication is not associated with the current_user so lets | |
# associate the authentication | |
@authentication.user = current_user | |
@authentication.save | |
redirect_to root_path, notice: "Account successfully authenticated" | |
end | |
else # no user is signed_in | |
if @authentication.user.present? | |
# The authentication we found had a user associated with it so let's | |
# just log them in here | |
self.current_user = @authentication.user | |
redirect_to root_path, notice: "Signed in!" | |
else | |
# The authentication has no user assigned and there is no user signed in | |
# Our decision here is to create a new account for the user | |
# But your app may do something different (eg. ask the user | |
# if he already signed up with some other service) | |
if @authentication.provider == 'identity' | |
u = User.find(@authentication.uid) | |
# If the provider is identity, then it means we already created a user | |
# So we just load it up | |
else | |
# otherwise we have to create a user with the auth hash | |
u = User.create_with_omniauth(auth) | |
# NOTE: we will handle the different types of data we get back | |
# from providers at the model level in create_with_omniauth | |
end | |
# We can now link the authentication with the user and log him in | |
u.authentications << @authentication | |
self.current_user = u | |
redirect_to root_path, notice: "Welcome to The app!" | |
end | |
end | |
end | |
def destroy | |
self.current_user = nil | |
redirect_to root_path, notice: "Signed out!" | |
end | |
def failure | |
redirect_to root_path, alert: "Authentication failed, please try again." | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# == Schema Information | |
# | |
# Table name: users | |
# | |
# id :integer not null, primary key | |
# name :string(255) | |
# email :string(255) | |
# created_at :datetime not null | |
# updated_at :datetime not null | |
# password_digest :string(255) | |
class User < OmniAuth::Identity::Models::ActiveRecord | |
attr_accessible :email, :name, :password, :password_confirmation | |
has_many :authentications | |
email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i | |
validates :email, :presence => true, | |
:format => { :with => email_regex }, | |
:uniqueness => { :case_sensitive => false } | |
def self.create_with_omniauth(auth) | |
# you should handle here different providers data | |
# eg. case auth['provider'] .. | |
create(name: auth['info']['name']) | |
# IMPORTANT: when you're creating a user from a strategy that | |
# is not identity, you need to set a password, otherwise it will fail | |
# I use: user.password = rand(36**10).to_s(36) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class UsersController < ApplicationController | |
def new | |
@user = env['omniauth.identity'] ||= User.new | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for this and your article (http://bernardi.me/using-multiple-omniauth-providers-with-omniauth-identity-on-the-main-user-model/). I've been trying to piece it together with information from http://railscasts.com/episodes/235-devise-and-omniauth-revised?view=comments, but no success. Yet!
Do you know of any resources that show how to hook this all up with the devise gem? Thanks!