Skip to content

Instantly share code, notes, and snippets.

@sundevilyang
Forked from zernel/Gemfile
Created October 2, 2012 06:09
Show Gist options
  • Save sundevilyang/3816654 to your computer and use it in GitHub Desktop.
Save sundevilyang/3816654 to your computer and use it in GitHub Desktop.
Devise authentication with multiple provider
class Authorization < ActiveRecord::Base
attr_accessible :provider, :uid, :user_id
belongs_to :user, :inverse_of => :authorizations
end
Devise.setup do |config|
...
# These oauth key and secret are use for localhost. Please replace them if necessary
config.omniauth :github, 'a55eb780a5a66bc2fabe', 'b531490bdcc4fcbb3e05bdca2e75e60b8ad9ba12'
config.omniauth :facebook, "283956394958478", "fdfedf11fba5c4e77e87a748aad36cc9"
config.omniauth :google_oauth2, '950211539633-6sh58gmv2mc39jn8m6b6uo9i5po6qkjh.apps.googleusercontent.com', 'pvDaViwlfKROcMTxhauo76Gu'
#config.omniauth :twitter, "xfOsUPR6WPYzs3EXBbrag", "jxWQdnKr0KnzteXZHbVaE2JtbE6PzuKjOs9PnkeEag"
end
gem 'devise'
gem 'omniauth'
gem 'omniauth-github'
gem "omniauth-twitter"
gem "omniauth-facebook"
gem "omniauth-google-oauth2"
# encoding: utf-8
class User
module OmniauthCallbacks
["github","google_oauth2","twitter","facebook"].each do |provider|
define_method "find_or_create_for_#{provider}" do |response|
uid = response["uid"]
data = response["info"]
if user = Authorization.where("provider" => provider , "uid" => uid).first.try(:user)
user
elsif user = User.find_by_email(data["email"])
user.authorizations << Authorization.new(:provider => provider, :uid => uid )
user
else
user = User.new(email: data["email"], username: data['nickname'] || data['name'])
if user.save(:validate => false)
user.authorizations << Authorization.new(:provider => provider, :uid => uid )
return user
else
Rails.logger.warn("User.create_from_hash 失败,#{user.errors.inspect}")
return nil
end
end
end
end
end
end
# encoding: utf-8
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def self.provides_callback_for(*providers)
providers.each do |provider|
class_eval %Q{
def #{provider}
if not current_user.blank?
current_user.bind_service(env["omniauth.auth"])#Add an auth to existing
redirect_to edit_user_registration_path, :notice => "成功绑定了 #{provider} 帐号。"
else
@user = User.find_or_create_for_#{provider}(env["omniauth.auth"])
if @user.persisted?
flash[:notice] = "Signed in with #{provider.to_s.titleize} successfully."
sign_in_and_redirect @user, :event => :authentication, :notice => "登陆成功。"
else
redirect_to new_user_registration_url
end
end
end
}
end
end
provides_callback_for :github, :twitter, :google_oauth2, :facebook
# This is solution for existing accout want bind Google login but current_user is always nil
# https://github.com/intridea/omniauth/issues/185
def handle_unverified_request
true
end
end
class Users::RegistrationsController < Devise::RegistrationsController
def update
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email)
if resource.update_without_current_password(resource_params)
if is_navigational_format?
flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ?
:update_needs_confirmation : :updated
set_flash_message :notice, flash_key
end
sign_in resource_name, resource, :bypass => true
respond_with resource, :location => after_update_path_for(resource)
else
clean_up_passwords resource
respond_with resource
end
end
protected
def update_needs_confirmation?(resource, previous)
resource.respond_to?(:pending_reconfirmation?) &&
resource.pending_reconfirmation? &&
previous != resource.unconfirmed_email
end
end
devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }
rails g model Authorization provider:string user_id:integer uid:string
rake db:migrate
class User < ActiveRecord::Base
extend OmniauthCallbacks
has_many :authorizations, :dependent => :destroy
...
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
...
def bind_service(response)
provider = response["provider"]
uid = response["uid"]
authorizations.create(:provider => provider , :uid => uid )
end
def update_without_current_password(params, *options)
params.delete(:current_password)
if params[:password].blank?
params.delete(:password)
params.delete(:password_confirmation) if params[:password_confirmation].blank?
end
result = update_attributes(params, *options)
clean_up_passwords
result
end
end
class CreateAuthorizations < ActiveRecord::Migration
def change
create_table :authorizations do |t|
t.string :provider
t.integer :user_id
t.string :uid
t.timestamps
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment