문제

I'm trying to create a script which will post temperature readings from a remote device to my website. I'm testing it locally for now and I'm running into this error when trying to post:

Error when running the script

/home/map7/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/mechanize-2.7.3/lib/mechanize/http/agent.rb:720:in `
response_authenticate': 401 => Net::HTTPUnauthorized for http://localhost:3000/temperatures.json -- WWW-Authenticate header missing in response (Mechanize::UnauthorizedError)                                                       
from /home/map7/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/mechanize-2.7.3/lib/mechanize/http/agent.rb:302:in `fetch'                                                                                               
from /home/map7/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/mechanize-2.7.3/lib/mechanize.rb:526:in `request_with_entity'                                                                                            
from /home/map7/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/mechanize-2.7.3/lib/mechanize.rb:480:in `post'                                                                                                           
from ./temperature_upload.rb:34:in `<main>'

Error in rails logs

Started POST "/temperatures.json" for 127.0.0.1 at 2014-02-10 22:46:47 +1100
Processing by TemperaturesController#create as JSON
  Parameters: {"temperature"=>{"temperature"=>"29"}}
WARNING: Can't verify CSRF token authenticity
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
   (0.0ms)  begin transaction
   (0.0ms)  commit transaction
Completed 401 Unauthorized in 2ms

My script

#!/usr/bin/env ruby
#
# EG: http://mechanize.rubyforge.org/GUIDE_rdoc.html

require 'mechanize'

HOST="http://localhost:3000"

# Setup Mechanize
agent = Mechanize.new
page =agent.get('http://localhost:3000/users/sign_in')

# Get user details
begin
  string = IO.read("#{ENV['HOME']}/.details")
rescue
  exit
end

json=JSON.parse(string)

# Login to my winesite
login_form = page.form("login")
login_form.field_with(type: "email").value = json["email"]
login_form.field_with(type: "password").value = json["password"]
page = agent.submit(login_form)

headers = { 'Content-Type' => 'application/json', 'Accept' => 'application/json'}
agent.post("#{HOST}/temperatures.json", '{"temperature":{"temperature": "29"}}', headers)

If I add the following to my controller then it will post. Is there a way to post without having to disable this:

skip_before_filter :verify_authenticity_token
도움이 되었습니까?

해결책

There's a couple of things you can do.

  1. Skip before filter for some actions only (using :only parameter).
  2. Add an additional step: go to the temperatures form and post through the button on this form.
  3. Go to the temperatures form, extract CSRF tokens from it and POST using these tokens.

However, the right way to do it is to separate security measures for a JSON API and html forms. You could implement some kind of key-based authorization to access API, or use already implemented solution (for example Grape).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top