【问题标题】:CORS Issue with Rails 4, omniauth-facebook, rack-cors, HerokuRails 4、omniauth-facebook、rack-cors、Heroku 的 CORS 问题
【发布时间】:2015-09-11 00:07:05
【问题描述】:

总结:

我遇到了 CORS 问题。我正在尝试从带有 Rails API 的 React 应用程序向 Facebook 进行身份验证。

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

我能够登录到 facebook 并在回调时创建会话,但 facebook 设置的 cookie 没有被omniauth 获取。我使用omniauth-facebook 客户端身份验证。

我认为问题出在我的 rack-cors 配置中。当我在 localhost:3000 上运行我的 api 时,它可以工作。

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

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

解决 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)
})

会话控制器:

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

应用控制器:

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

【问题讨论】:

  • 您的 API 控制器中可能需要 skip_before_action :verify_authenticity_token
  • 嗨,Tute,我在上面的问题中添加了我的 SessionsController 和 ApplicationController。我按照您的建议更改了我的 ApplicationController。但是,这并没有解决 CSRF 问题。
  • @Ravindra,很遗憾没有,我无法登录 facebook 和 google,但我收到了这条消息:请求中没有“Access-Control-Allow-Origin”标头资源。因此,不允许访问 Origin 'null'。
  • 您能否同时发布 Facebook 登录请求以及对您的 API 的调用的请求和响应标头和正文?尽管您进行了配置,但错误似乎是在抱怨标头不存在,因此您应该确保它存在。

标签: ruby-on-rails heroku cors omniauth-facebook


【解决方案1】:

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

这是因为是跨域调用。

更多详情请见http://api.jquery.com/jquery.ajax/

【讨论】:

    【解决方案2】:

    我在使用 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
     }
    

    这是来自设计 wiki 的链接,其中提到了该问题。我知道您没有使用设计,但它可能会有所帮助。 https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

    【讨论】:

      【解决方案3】:

      也许 CORS 中间件不适合您。我没有这方面的经验,但也许只是在您的应用程序控制器中添加一个之前的操作,然后执行以下操作...只是为了确保您知道适当的标头在那里。

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

      【讨论】:

      • 谢谢。我会试一试。与此同时,我决定实现其他一些功能。
      猜你喜欢
      • 2013-11-25
      • 2013-11-21
      • 2016-07-13
      • 2019-05-21
      • 2020-09-03
      • 1970-01-01
      • 2014-06-20
      • 2023-03-28
      • 2021-07-25
      相关资源
      最近更新 更多