在张贴的Rails 3.2.11和RSpec生JSON数据(POSTing raw JSON dat

2019-07-19 15:46发布

为了确保我的应用程序不会受到这个漏洞 ,我想创建RSpec的控制器测试来覆盖它。 为了做到这一点,我需要能够发布生JSON,但我还没有似乎找到一个方法来做到这一点。 在做一些研究,我确定有至少曾经是一个办法做到这一点使用RAW_POST_DATA头,但是这似乎并没有工作了:

it "should not be exploitable by using an integer token value" do
  request.env["CONTENT_TYPE"] = "application/json"
  request.env["RAW_POST_DATA"]  = { token: 0 }.to_json
  post :reset_password
end

当我看到params哈希表,令牌根本没有设置,它只是包含{ "controller" => "user", "action" => "reset_password" } 我在尝试时使用XML,甚至试图只使用普通邮寄资料时,在所有情况下,它似乎没有设置期限相同的结果。

我知道,随着近期Rails的漏洞,参数被散列的方式改变了,但仍有通过RSpec的发布原始数据的方法吗? 我可以以某种方式直接使用Rack::Test::Methods

Answer 1:

据我已经能够告诉,发送原始POST数据是不再可能内的控制器规范。 但是,它可以很容易地在要求规范进行:

describe "Example", :type => :request do
  params = { token: 0 }
  post "/user/reset_password", params.to_json, { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' }
  #=> params contains { "controller" => "user", "action" => "reset_password", "token" => 0 }
end


Answer 2:

这是生JSON发送到一个控制器动作(Rails的3+)的方式:

比方说,我们有这样的路线:

post "/users/:username/posts" => "posts#create"

让我们说你希望身体是你做阅读JSON:

JSON.parse(request.body.read)

然后,你的测试将是这样的:

it "should create a post from a json body" do
  json_payload = '{"message": "My opinion is very important"}'
  post :create, json_payload, {format: 'json', username: "larry" }
end

{format: 'json'}是使之成为现实的魔力。 此外,如果我们看一下源的TestCase#后http://api.rubyonrails.org/classes/ActionController/TestCase/Behavior.html#method-i-process你可以看到,它会将第一个参数的动作后( json_payload),如果它是一个字符串,它将设置为原料后的身体,并解析ARGS正常的休息。

同样重要的是指出,rspec的仅仅是对Rails的测试架构之上的DSL。 该post上述方法是ActionController的::测试用例#交而不是一些rspec的发明。



Answer 3:

我们已经在我们的测试控制器进行明确设置的RAW_POST_DATA:

before do
  @request.env['RAW_POST_DATA'] = payload.to_json
  post :my_action
end


Answer 4:

导轨5例子:

RSpec.describe "Sessions responds to JSON", :type => :request do

  scenario 'with correct authentication' do
    params = {id: 1, format: :json}
    post "/users/sign_in", params: params.to_json, headers: { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' }
    expect(response.header['Content-Type']).to include 'application/json'
  end
end


Answer 5:

这里是一个控制器测试发送原始JSON数据的一个完整的工作示例:

describe UsersController, :type => :controller do

  describe "#update" do
    context 'when resource is found' do
      before(:each) do
        @user = FactoryGirl.create(:user)
      end

      it 'updates the resource with valid data' do
        @request.headers['Content-Type'] = 'application/vnd.api+json'
        old_email = @user.email
        new_email = Faker::Internet.email
        jsondata = 
        {
          "data" => {
            "type" => "users",
            "id" => @user.id,
            "attributes" => {
              "email" => new_email
            }
          }
        }

        patch :update, jsondata.to_json, jsondata.merge({:id => old_id})

        expect(response.status).to eq(200)
        json_response = JSON.parse(response.body)
        expect(json_response['data']['id']).to eq(@user.id)
        expect(json_response['data']['attributes']['email']).to eq(new_email)
      end
    end
  end
end

最重要的部分是:

@request.headers['Content-Type'] = 'application/vnd.api+json'

patch :update, jsondata.to_json, jsondata.merge({:id => old_id})

第一种方式是确保内容类型是否正确设置你的要求,这是非常简单的。 第二部分是给我头疼了几个小时,我最初的做法是有点不同,但事实证明,有一个Rails的错误 ,这使我们无法在功能测试发送原始post数据(但允许我们在集成测试),这是一个丑陋的解决办法,但它的工作原理(上轨4.1.8和RSpec护栏3.0.0)。



文章来源: POSTing raw JSON data with Rails 3.2.11 and RSpec