首页 文章

CORS问题与Rails 4,omniauth-facebook,rack-cors,Heroku

提问于
浏览
3

摘要:

我有一个CORS问题 . 我正试图通过带有Rails API的React应用程序对Facebook进行身份验证 .

我的应用程序在localhost:8080上运行,我的api在Heroku上运行 .

我可以登录到facebook并在回调时创建一个会话,但是由facebook设置的cookie不会被omniauth选中 . 我使用omniauth-facebook客户端身份验证 .

我认为这个问题出现在我的机架式配置中 . 当我在localhost:3000上运行我的api时,它可以工作 .

之前,我收到了错误 csrf-detected ,但是通过将 provider_ignores_state: true 添加到omniauth配置中解决了这个问题 . 后来,我发现cors要求传递cookie需要 xhrFields: { withCredentials: true } .

最终解决方案:最后,我通过将我的应用程序部署到带有域 example.com 的AWS 53来解决此问题,并在Heroku上创建CNAMES'api.example.com`到我的api .

让CNAMES得到解决需要一天的时间 . 您可以使用命令host example.com 和host api.example.com 在终端中测试您的设置 .

替代解决方案是使用nginx作为代理 .

版本:

Rails 4.2.2
Omniauth-facebook 3.0.0
Omniauth-oauth2 1.4.0
Rack-cors 0.4.0

问题:

Getting error: no_authorization_code.

路线:

namespace :api do
    match "/auth/:provider/callback", to: "sessions#create", via: [:get, :post]
    get "/auth/failure", to: "sessions#failure"
    get "/logout", to: "sessions#destroy"

application.rb中:

config.middleware.insert_before 0, "Rack::Cors" do
  allow do
    origins "localhost:8000", "example.com"
    resource "*",
      :headers => :any,
      :methods => [:get, :post, :delete, :put, :options],
      :max_age => 1728000
  end
end

Omniauth.rb:

OmniAuth.config.path_prefix = "/api/auth"

OmniAuth.config.logger = Rails.logger

OmniAuth.config.on_failure = Proc.new { |env|
  OmniAuth::FailureEndpoint.new(env).redirect_to_failure
}

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :facebook,
    Rails.application.secrets.facebook_key,
    Rails.application.secrets.facebook_secret, {
      provider_ignores_state: true,
      client_options: {
        :ssl => { :ca_file => "/usr/lib/ssl/certs/ca-certificates.crt" }
      }
    }
  provider :identity,
    fields: [:email],
    on_failed_registration: lambda { |env|
      Api::IdentitiesController.action(:new).call(env)
    }
end

Secret.yml:

development:
facebook_key: <%= ENV["FACEBOOK_KEY"] %>
facebook_secret: <%= ENV["FACEBOOK_SECRET"] %>

客户:

$.ajax({
  url: http://localhost:3000/api/auth/facebook,
  dataType: "json",
  type: "GET",
  xhrFields: { withCredentials: true },
  success: function(data) {
  }.bind(this),
  error: function(xhr, status, err) {
  }.bind(this)
})

SessionsController:

module Api
  class SessionsController < ApplicationController
    skip_before_action :verify_authenticity_token
    skip_before_action :restrict_access
    skip_after_action :verify_authorized

def create
  user = User.from_omniauth(auth_params)
  session[:user_id] = user.id
  render json: user, status: :ok
end

def destroy
  session[:user_id] = nil
  render json: {}, status: :ok
end

def failure
  render json: { errors: params[:message] }, status: :unauthorized
end

private

def auth_params
  request.env.fetch("omniauth.auth")
end end end

ApplicationsController:

class ApplicationController < ActionController::Base
  include Pundit
  before_action :restrict_access
  after_action :verify_authorized, :except => :index
  after_action :verify_policy_scoped, :only => :index

    respond_to :json

    protected

    attr_reader :current_user

    # Allows access to current_user in serializators.
    serialization_scope :current_user

    def restrict_access
      authenticate_or_request_with_http_token do |token, options|
      @current_user = User.find_by(token: token)
    end
  end
end

3 回答

  • 0

    我在使用Devise在rails应用程序中执行omniauth时遇到了同样的问题 . 最终,问题在于Facebook在7月初更新了他们的API,现在要求你专门询问 info_fields param中的字段 .

    我会尝试更改您的 omniauth.rb 以包括:

    provider :facebook,
     Rails.application.secrets.facebook_key,
     Rails.application.secrets.facebook_secret, {
       :scope => "email, user_birthday",
       :info_fields => "email, user_birthday", #<== this made the difference for me
       provider_ignores_state: true
     }
    

    这里's a link from the devise wiki that mentions the issue. I know you'没有使用设计,但它可能会有所帮助 . https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

  • 2

    也许CORS中间件不适合你 . 我没有使用它的经验,但可能只是在应用程序控制器中添加一个before操作,并执行以下操作...只是为了确保您知道相应的 Headers .

    response.headers["Access-Control-Allow-Origin"] = "http://localhost:8080"
    
  • 0

    我发现我的Ajax调用需要包含 xhrFields: { withCredentials: true } 才能将cookie传递给omniauth .

    这是因为它是跨域调用 .

    有关详细信息,请参阅http://api.jquery.com/jquery.ajax/ .

相关问题