Rails - json/xml 请求的 InvalidAuthenticityToken
由于某种原因,我在使用 json 或 xml 向我的应用程序发出发布请求时收到 InvalidAuthenticityToken。 我的理解是,rails 应该只需要 html 或 js 请求的真实性令牌,因此我不应该遇到这个错误。 到目前为止,我找到的唯一解决方案是对我想通过 API 访问的任何操作禁用 protected_from_forgery,但由于显而易见的原因,这并不理想。 想法?
def create
respond_to do |format|
format.html
format.json{
render :json => Object.create(:user => @current_user, :foo => params[:foo], :bar => params[:bar])
}
format.xml{
render :xml => Object.create(:user => @current_user, :foo => params[:foo], :bar => params[:bar])
}
end
end
这就是每当我将请求传递给操作时我在日志中得到的内容:
Processing FooController#create to json (for 127.0.0.1 at 2009-08-07 11:52:33) [POST]
Parameters: {"foo"=>"1", "api_key"=>"44a895ca30e95a3206f961fcd56011d364dff78e", "bar"=>"202"}
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
thin (1.2.2) lib/thin/connection.rb:76:in `pre_process'
thin (1.2.2) lib/thin/connection.rb:74:in `catch'
thin (1.2.2) lib/thin/connection.rb:74:in `pre_process'
thin (1.2.2) lib/thin/connection.rb:57:in `process'
thin (1.2.2) lib/thin/connection.rb:42:in `receive_data'
eventmachine (0.12.8) lib/eventmachine.rb:242:in `run_machine'
eventmachine (0.12.8) lib/eventmachine.rb:242:in `run'
thin (1.2.2) lib/thin/backends/base.rb:57:in `start'
thin (1.2.2) lib/thin/server.rb:156:in `start'
thin (1.2.2) lib/thin/controllers/controller.rb:80:in `start'
thin (1.2.2) lib/thin/runner.rb:174:in `send'
thin (1.2.2) lib/thin/runner.rb:174:in `run_command'
thin (1.2.2) lib/thin/runner.rb:140:in `run!'
thin (1.2.2) bin/thin:6
/opt/local/bin/thin:19:in `load'
/opt/local/bin/thin:19
For some reason I'm getting an InvalidAuthenticityToken when making post requests to my application when using json or xml. My understanding is that rails should require an authenticity token only for html or js requests, and thus I shouldn't be encountering this error. The only solution I've found thus far is disabling protect_from_forgery for any action I'd like to access through the API, but this isn't ideal for obvious reasons. Thoughts?
def create
respond_to do |format|
format.html
format.json{
render :json => Object.create(:user => @current_user, :foo => params[:foo], :bar => params[:bar])
}
format.xml{
render :xml => Object.create(:user => @current_user, :foo => params[:foo], :bar => params[:bar])
}
end
end
and this is what I get in the logs whenever I pass a request to the action:
Processing FooController#create to json (for 127.0.0.1 at 2009-08-07 11:52:33) [POST]
Parameters: {"foo"=>"1", "api_key"=>"44a895ca30e95a3206f961fcd56011d364dff78e", "bar"=>"202"}
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
thin (1.2.2) lib/thin/connection.rb:76:in `pre_process'
thin (1.2.2) lib/thin/connection.rb:74:in `catch'
thin (1.2.2) lib/thin/connection.rb:74:in `pre_process'
thin (1.2.2) lib/thin/connection.rb:57:in `process'
thin (1.2.2) lib/thin/connection.rb:42:in `receive_data'
eventmachine (0.12.8) lib/eventmachine.rb:242:in `run_machine'
eventmachine (0.12.8) lib/eventmachine.rb:242:in `run'
thin (1.2.2) lib/thin/backends/base.rb:57:in `start'
thin (1.2.2) lib/thin/server.rb:156:in `start'
thin (1.2.2) lib/thin/controllers/controller.rb:80:in `start'
thin (1.2.2) lib/thin/runner.rb:174:in `send'
thin (1.2.2) lib/thin/runner.rb:174:in `run_command'
thin (1.2.2) lib/thin/runner.rb:140:in `run!'
thin (1.2.2) bin/thin:6
/opt/local/bin/thin:19:in `load'
/opt/local/bin/thin:19
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
添加到 andymism 的答案中,您可以使用它在每个 POST 请求中应用 TOKEN 的默认包含:
Adding up to andymism's answer you can use this to apply the default inclusion of the TOKEN in every POST request:
只要 JavaScript 位于 Rails 提供的网站上(例如:JS 片段;或通过 webpacker 管理的 React 应用程序),您就可以使用
application.html 中包含的
。csrf_meta_tags
中的值默认为.erb在
application.html.erb
中:因此在网站的 HTML 中:
从
content
属性中获取令牌并在请求中使用它:这类似于 @andrewle 的答案但不需要额外的令牌。
As long as the JavaScript lives on the website served by Rails (for example: a JS snippet; or React app managed via webpacker) you can use the the value in
csrf_meta_tags
included inapplication.html.erb
by default.In
application.html.erb
:Therefore in the HTML of your website:
Grab the token from the
content
property and use it in the request:This is similar to @andrewle's answer but there's no need for an additional token.
从Rails 4.2开始,我们有另一种方法是在Rails应用程序中使用skip_before_filter来避免verify_authenticity_token:
这将使curl完成其工作。
Ruby on Rails 4.2 发行说明:https://guiarails.com.br/4_2_release_notes.html
Since Rails 4.2, we have another way is to avoid verify_authenticity_token using skip_before_filter in your Rails App:
This will let curl to do its job.
Ruby on Rails 4.2 Release Notes: https://guiarails.com.br/4_2_release_notes.html
要添加 Fernando 的答案,如果您的控制器同时响应 json 和 html,您可以使用:
To add to Fernando's answer, if your controller responds to both json and html, you can use:
启用
protect_from_forgery
后,Rails 需要为任何非 GET 请求提供真实性令牌。 Rails 会自动在使用表单助手创建的表单或使用 AJAX 助手创建的链接中包含真实性令牌——因此在正常情况下,您不必考虑它。如果您没有使用内置的 Rails 表单或 AJAX 帮助程序(也许您正在使用不显眼的 JS 或使用 JS MVC 框架),您必须自己在客户端设置令牌并将其与您的提交 POST 请求时的数据。 您可以在布局的
中放置这样一行:
然后您的 AJAX 函数将使用您的其他数据发布令牌(例如使用 jQuery):
With
protect_from_forgery
enabled, Rails requires an authenticity token for any non-GET requests. Rails will automatically include the authenticity token in forms created with the form helpers or links created with the AJAX helpers--so in normal cases, you won't have to think about it.If you're not using the built-in Rails form or AJAX helpers (maybe you're doing unobstrusive JS or using a JS MVC framework), you'll have to set the token yourself on the client side and send it along with your data when submitting a POST request. You'd put a line like this in the
<head>
of your layout:Then your AJAX function would post the token with your other data (example with jQuery):
我遇到了类似的情况,问题是我没有通过正确的内容类型标头发送 - 我正在请求
text/json
而我应该请求application/json
。我使用以下
curl
来测试我的应用程序(根据需要进行修改):或者您可以将 JSON 保存到本地文件并像这样调用
curl
:当我更改内容时在右侧输入 headers
application/json
我所有的麻烦都消失了,我不再需要禁用伪造保护。I had a similar situation and the problem was that I was not sending through the right content type headers - I was requesting
text/json
and I should have been requestingapplication/json
.I used
curl
the following to test my application (modify as necessary):Or you can save the JSON to a local file and call
curl
like this:When I changed the content type headers to the right
application/json
all my troubles went away and I no longer needed to disable forgery protection.