使用 OmniAuth 进行设计

Devise with OmniAuth Facebook

我无法将 deviseomniauth-facebook

整合

我的演示应用正在使用:

我遵循了 Wiki 页面上的以下指南:https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview 但在创建用户时遇到问题。

它将让用户登录并将应用程序添加到用户的 Facebook(在应用程序设置中),但它会将帐户注册到 User 模型。

# Gemfile
source 'https://rubygems.org'

gem 'rails', '~> 5.0.0'

gem 'devise'
gem 'pundit'
gem 'omniauth-facebook' 

# Gemfile.lock for the 3 authorization and authentication gems
GEM
  remote: https://rubygems.org/
  remote: https://rails-assets.org/
  specs:

    devise (4.2.0)
      bcrypt (~> 3.0)
      orm_adapter (~> 0.1)
      railties (>= 4.1.0, < 5.1)
      responders

      warden (~> 1.2.3)
    pundit (1.1.0)

    omniauth (1.3.1)
      hashie (>= 1.2, < 4)
      rack (>= 1.0, < 3)
    omniauth-facebook (4.0.0)
      omniauth-oauth2 (~> 1.2)
    omniauth-oauth2 (1.4.0)
      oauth2 (~> 1.0)
      omniauth (~> 1.2)

用户模型的架构。

我添加了迁移 provider:stringuid:string

# == Schema Information
#
# Table name: users
#
#  id                     :integer          not null, primary key
#  email                  :string           default(""), not null
#  encrypted_password     :string           default(""), not null
#  reset_password_token   :string
#  reset_password_sent_at :datetime
#  remember_created_at    :datetime
#  sign_in_count          :integer          default(0), not null
#  current_sign_in_at     :datetime
#  last_sign_in_at        :datetime
#  current_sign_in_ip     :inet
#  last_sign_in_ip        :inet
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#  name                   :string           default(""), not null
#  provider               :string
#  uid                    :string

ApplicationController包含punditdevise代码:

class ApplicationController < ActionController::Base
  include Pundit
  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  protect_from_forgery with: :exception

  before_action :configure_permitted_parameters, if: :devise_controller?

  private

    def user_not_authorized
      flash[:error] = "You are not authorized to perform this action."
      redirect_to(request.referrer || root_path)
    end

  protected

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
      devise_parameter_sanitizer.permit(:account_update, keys: [:name])
    end
end

我已将 config/initializers/devise.rb 配置为在 omniauth 配置中包含 :facebook

# File: config/initializers/devise.rb
# Use this hook to configure devise mailer, warden hooks and so forth.
# Many of these configuration options can be set straight in your model.
Devise.setup do |config|
  require 'devise/orm/active_record'

  config.case_insensitive_keys = [:email]
  config.strip_whitespace_keys = [:email]
  config.skip_session_storage = [:http_auth]
  config.stretches = Rails.env.test? ? 1 : 11
  config.reconfirmable = true
  config.password_length = 6..128
  config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
  config.sign_out_via = :delete

  # ==> OmniAuth
  # Add a new OmniAuth provider. Check the wiki for more information on setting
  # up on your models and hooks.
  # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
  config.omniauth :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'], callback_url: ENV['FACEBOOK_CALLBACK_URL'], scope: 'email', info_fields: 'email,name'
end

我已将 omniauthable 添加到 User 模型。

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :omniauthable, omniauth_providers: [:facebook]

  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.name = auth.info.name
      user.email = auth.info.email
      user.password = Devise.friendly_token[0,20]
    end
  end

  def self.new_with_session(params, session)
    super.tap do |user|
      if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
        user.email = data["email"] if user.email.blank?
      end
    end
  end
end

我创建了一个 OmniauthCallbacksController 来处理登录请求。

# File: app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    @user = User.from_omniauth(request.env["omniauth.auth"])

    if @user.persisted?
      sign_in_and_redirect @user, event: :authentication #this will throw if @user is not activated
      set_flash_message(:notice, :success, kind: "Facebook") if is_navigational_format?
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end

  def failure
    redirect_to root_path
  end
end

Routes 我添加了以下内容:

# File: config/routes.rb
Rails.application.routes.draw do
  devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }

  root 'pages#index'
end

已将 "Sign in with Facebook" link 添加到 devise sessions#new 视图。

# File: app/views/devise/sessions/new.html.erb
<div class="login">
  <%= link_to "Sign in with Facebook", user_facebook_omniauth_authorize_path %>
 # This is the link it creates: <a href="/users/auth/facebook">Sign in with Facebook</a>
</div>

用户流:

  1. 点击 "Sign in with Facebook"
  2. 用户被转发到 Facebook 的 Oauth url,并在用户点击 "OK"
  3. 时出现 'Continue as User' 提示
  4. 用户返回到应用程序,但用户未在数据库中注册
  5. url 是一长串参数 codestate (检查 *NB

*注意 Return url 来自 Facebook:

http://localhost:3000/?code=REALLYLONGHASHOFCHARACTERS&state=ANOTHERSETOFREALLYLONGHASHOFCHARACTERS

development.log显示:

Started GET "/users/auth/facebook" for ::1 at 2016-08-10 18:43:26 +1000
I, [2016-08-10T18:43:26.084371 #2292]  INFO -- omniauth: (facebook) Request phase initiated.
Started GET "/users/auth/facebook" for ::1 at 2016-08-10 18:43:26 +1000
I, [2016-08-10T18:43:26.521627 #2292]  INFO -- omniauth: (facebook) Request phase initiated.
Started GET "/?code=REALLYLONGHASHOFCHARACTERS&state=ANOTHERSETOFREALLYLONGHASHOFCHARACTERS" for ::1 at 2016-08-10 18:44:19 +1000
Processing by ListingsController#index as HTML
  Parameters: {"code"=>"REALLYLONGHASHOFCHARACTERS", "state"=>"ANOTHERSETOFREALLYLONGHASHOFCHARACTERS"}

我认为它没有命中 Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController,因为我在 facebook 操作上放置了 raise "Error",但它没有引发任何错误。当 运行 Rails routes

时我看不到 omniauth_callbacks: "users/omniauth_callbacks"

检查路线显示:

# Routes

||                           Prefix Verb     URI Pattern                             Controller#Action
||                 new_user_session GET      /users/sign_in(.:format)                devise/sessions#new
||                     user_session POST     /users/sign_in(.:format)                devise/sessions#create
||             destroy_user_session DELETE   /users/sign_out(.:format)               devise/sessions#destroy
|| user_facebook_omniauth_authorize GET|POST /users/auth/facebook(.:format)          users/omniauth_callbacks#passthru
||  user_facebook_omniauth_callback GET|POST /users/auth/facebook/callback(.:format) users/omniauth_callbacks#facebook
||                    user_password POST     /users/password(.:format)               devise/passwords#create
||                new_user_password GET      /users/password/new(.:format)           devise/passwords#new
||               edit_user_password GET      /users/password/edit(.:format)          devise/passwords#edit
||                                  PATCH    /users/password(.:format)               devise/passwords#update
||                                  PUT      /users/password(.:format)               devise/passwords#update
||         cancel_user_registration GET      /users/cancel(.:format)                 devise/registrations#cancel
||                user_registration POST     /users(.:format)                        devise/registrations#create
||            new_user_registration GET      /users/sign_up(.:format)                devise/registrations#new
||           edit_user_registration GET      /users/edit(.:format)                   devise/registrations#edit
||                                  PATCH    /users(.:format)                        devise/registrations#update
||                                  PUT      /users(.:format)                        devise/registrations#update
||                                  DELETE   /users(.:format)                        devise/registrations#destroy
||                             root GET      /                                       pages#index

我不确定从这里开始做什么。非常感谢任何帮助和见解。

现在一切正常。

callback_url错误有关。

来自日志:

Started GET "/users/auth/facebook" for ::1 at 2016-08-10 18:43:26 +1000
I, [2016-08-10T18:43:26.084371 #2292]  INFO -- omniauth: (facebook) Request phase initiated.
Started GET "/users/auth/facebook" for ::1 at 2016-08-10 18:43:26 +1000
I, [2016-08-10T18:43:26.521627 #2292]  INFO -- omniauth: (facebook) Request phase initiated.
Started GET "/?code=REALLYLONGHASHOFCHARACTERS&state=ANOTHERSETOFREALLYLONGHASHOFCHARACTERS" for ::1 at 2016-08-10 18:44:19 +1000

日志文件的最后一行显示它不会正确 url:

Started GET "/?code=REALLYLONGHASHOFCHARACTERS&state=ANOTHERSETOFREALLYLONGHASHOFCHARACTERS" for ::1 at 2016-08-10 18:44:19 +1000

初始化配置显示:

config.omniauth :facebook, 
   ENV['FACEBOOK_APP_ID'],
   ENV['FACEBOOK_APP_SECRET'],
   callback_url: ENV['FACEBOOK_CALLBACK_URL'],
   scope: 'email', info_fields: 'email,name'

callback_urlhttp://localhost:3000,这是不正确的。

我将 callback_urlhttp://localhost:3000 更改为 http://localhost:3000/users/auth/facebook/callback

它现在正在运行,我希望这对以后的人有所帮助。