根据Rspec的说法,为什么没有机架过滤来过滤传入的请求

时间:2017-05-17 21:14:59

标签: ruby-on-rails rspec cors rails-api rack-cors

我希望我的Rails 5 API专用应用程序(现在在http://localhost:3000上运行)仅接受来自我的NodeJS前端应用程序的请求,现在在http://localhost:8888上运行。< / p>

所以我像这样配置了/config/initializers/cors.rb

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins "http://localhost:8888"
    resource "*",
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

我写了这个测试:

#/spec/request/cors_request_spec.rb

RSpec.feature "CORS protection", type: :request do
  it "should accept a request from a whitelisted domain" do
    get "/api/v1/bodies.json", nil, "HTTP_ORIGIN": "http://localhost:8888"
    expect(response.status).to eql(200)
  end
  it "should reject a request from a non-whitelisted domain" do
    get "/api/v1/bodies.json", nil, "HTTP_ORIGIN": "https://foreign.domain"
    expect(response.status).to eql(406)
  end
end

第一个测试按预期传递。但第二个是失败,响应代码为200.为什么?

(顺便说一句,我没有与406响应代码结婚;只是表示请求无法完成的代码。)

1 个答案:

答案 0 :(得分:6)

CORS配置不会阻止服务器根据Origin请求标头的值接受请求。你不能只通过CORS配置来做到这一点。

在服务器上配置CORS支持时,服务器执行的所有操作都只是发送Access-Control-Allow-Origin响应头和其他CORS响应头。

CORS限制的实际执行仅由浏览器完成。它不是由服务器强制执行的。

协议的工作方式是,无论您在服务器端进行哪种CORS配置,服务器都会继续接受来自所有客户端的请求,否则会接收来自所有客户端的请求,因此来自所有来源的所有客户端都会继续从服务器就像它们原样一样。

因此,即使您在浏览器中发现错误,您的前端JavaScript代码中的跨源请求失败,您仍然可以在浏览器devtools中看到响应。

但仅仅因为您的浏览器可以看到响应并不意味着浏览器会将其暴露给您的前端JavaScript代码。浏览器仅将来自跨源请求的响应暴露给在特定来源运行的前端代码,如果请求被发送到opts-in的服务器通过使用允许该来源的Access-Control-Allow-Origin标头进行响应来允许请求。

因此,对于Origin请求标头与https://foreign.domain匹配的任何请求,问题中的配置代码段会导致浏览器在客户端发出消息,指出http://localhost:3000/api/v1/bodies.json不能已加载,因为响应中没有Access-Control-Allow-Origin响应标头(因为您的配置导致服务器仅在响应您列入白名单的来源时发送该标头)。

但是你可以通过CORS做到这一切。您无法通过在服务器端执行任何CORS配置来阻止服务器端接受和响应来自特定源的请求。如果你想这样做,你需要使用除CORS配置之外的其他东西。