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

摘要:

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

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

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

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

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

最终解决方案:最后,我通过将我的应用程序部署到AWS 53并使用域example.com来解决此问题,并在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:  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  :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 

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

这是因为它是跨域调用。

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

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

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

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

我会尝试更改你的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 } 

这是设计维基的一个链接,提到了这个问题。 我知道你没有使用设计,但它可能会有所帮助。 https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview