浏览代码

Twitter, Facebook, GitHub sign up (#16)

* Facebook, Twitter, GitHub login set up

* Typo fix
Miguel 6 年之前
父节点
当前提交
a5c9d555d1
共有 3 个文件被更改,包括 126 次插入0 次删除
  1. 78 0
      app/controllers/users/omniauth_callbacks_controller.rb
  2. 32 0
      app/models/service.rb
  3. 16 0
      template.rb

+ 78 - 0
app/controllers/users/omniauth_callbacks_controller.rb

@@ -0,0 +1,78 @@
+class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
+  before_action :set_service
+  before_action :set_user
+
+  attr_reader :service, :user
+
+  def facebook
+    handle_auth "Facebook"
+  end
+
+  def twitter
+    handle_auth "Twitter"
+  end
+
+  def github
+    handle_auth "Github"
+  end
+
+  private
+
+  def handle_auth(kind)
+    if service.present?
+      service.update(service_attrs)
+    else
+      user.services.create(service_attrs)
+    end
+
+    if user_signed_in?
+      flash[:notice] = "Your #{kind} account was connected."
+      redirect_to edit_user_registration_path
+    else
+      sign_in_and_redirect user, event: :authentication
+      set_flash_message :notice, :success, kind: kind
+    end
+  end
+
+  def auth
+    request.env['omniauth.auth']
+  end
+
+  def set_service
+    @service = Service.where(provider: auth.provider, uid: auth.uid).first
+  end
+
+  def set_user
+    if user_signed_in?
+      @user = current_user
+    elsif service.present?
+      @user = service.user
+    elsif User.where(email: auth.info.email).any?
+      # 5. User is logged out and they login to a new account which doesn't match their old one
+      flash[:alert] = "An account with this email already exists. Please sign in with that account before connecting your #{auth.provider.titleize} account."
+      redirect_to new_user_session_path
+    else
+      @user = create_user
+    end
+  end
+
+  def service_attrs
+    expires_at = auth.credentials.expires_at.present? ? Time.at(auth.credentials.expires_at) : nil
+    {
+        provider: auth.provider,
+        uid: auth.uid,
+        expires_at: expires_at,
+        access_token: auth.credentials.token,
+        access_token_secret: auth.credentials.secret,
+    }
+  end
+
+  def create_user
+    User.create(
+      email: auth.info.email,
+      #name: auth.info.name,
+      password: Devise.friendly_token[0,20]
+    )
+  end
+
+end

+ 32 - 0
app/models/service.rb

@@ -0,0 +1,32 @@
+class Service < ApplicationRecord
+  belongs_to :user
+
+  %w{ facebook twitter github }.each do |provider|
+    scope provider, ->{ where(provider: provider) }
+  end
+
+  def client
+    send("#{provider}_client")
+  end
+
+  def expired?
+    expires_at? && expires_at <= Time.zone.now
+  end
+
+  def access_token
+    send("#{provider}_refresh_token!", super) if expired?
+    super
+  end
+
+
+  def twitter_client
+    Twitter::REST::Client.new do |config|
+      config.consumer_key        = Rails.application.secrets.twitter_app_id
+      config.consumer_secret     = Rails.application.secrets.twitter_app_secret
+      config.access_token        = access_token
+      config.access_token_secret = access_token_secret
+    end
+  end
+
+  def twitter_refresh_token!(token); end
+end

+ 16 - 0
template.rb

@@ -14,6 +14,9 @@ def add_gems
   gem 'webpacker', '~> 3.0'
   gem 'sidekiq', '~> 5.0'
   gem 'foreman', '~> 0.84.0'
+  gem 'omniauth-facebook', '~> 4.0'
+  gem 'omniauth-twitter', '~> 1.4'
+  gem 'omniauth-github', '~> 1.3'
 end
 
 def add_users
@@ -98,6 +101,18 @@ def add_administrate
     "announcement_type: Field::Select.with_options(collection: Announcement::TYPES)"
 end
 
+def add_multiple_authentication
+    insert_into_file "config/routes.rb",
+    ', controllers: { omniauth_callbacks: "users/omniauth_callbacks" }',
+    after: "  devise_for :users"
+
+    insert_into_file "app/models/user.rb",
+    ', :omniauthable',
+    after: '         :recoverable, :rememberable, :trackable, :validatable'    
+
+    generate "model Service user:references provider uid access_token access_token_secret refresh_token expires_at:datetime auth:text"
+end
+
 # Main setup
 add_gems
 
@@ -108,6 +123,7 @@ after_bundle do
   add_foreman
   add_webpack
   add_announcements
+  add_multiple_authentication
 
   # Migrate
   rails_command "db:create"