问题
I was working on a new Rails 4 app (on Ruby 2.0.0-p0) when I ran into some authenticity token problems.
While writing a controller that responds to json (using the respond_to
class method), I got to the create
action I started getting ActionController::InvalidAuthenticityToken
exceptions when I tried to create a record using curl
.
I made sure I set -H \"Content-Type: application/json\"
and I set the data with -d \"<my data here>\"
but still no luck.
I tried writing the same controller using Rails 3.2 (on Ruby 1.9.3) and I got no authenticity token problems whatsoever. I searched around and I saw that there were some changes with authenticity tokens in Rails 4. From what I understand, they are no longer automatically inserted in forms anymore? I suppose this is somehow affecting non-HTML content types.
Is there any way to get around this without having to request a HTML form, snatching the authenticity token, then making another request with that token? Or am I completely missing something that\'s completely obvious?
Edit: I just tried creating a new record in a new Rails 4 app using a scaffold without changing anything and I\'m running into the same problem so I guess it\'s not something I did.
回答1:
I think I just figured it out. I changed the (new) default
protect_from_forgery with: :exception
to
protect_from_forgery with: :null_session
as per the comment in ApplicationController
.
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
You can see the difference by looking at the source for request_forgery_protecton.rb
, or, more specifically, the following lines:
In Rails 3.2:
# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
reset_session
end
In Rails 4:
def handle_unverified_request
forgery_protection_strategy.new(self).handle_unverified_request
end
Which will call the following:
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end
回答2:
Instead of turn off the csrf protection, it's better to add the following line of code into the form
<%= tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %>
and if you're using form_for or form_tag to generate the form, then it will automatically add the above line of code in the form
回答3:
Adding the following line into the form worked for me:
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
回答4:
I don't think it's good to generally turn off CSRF protection as long as you don't exclusively implement an API.
When looking at the Rails 4 API documentation for ActionController I found that you can turn off forgery protection on a per controller or per method base.
For example to turn off CSRF protection for methods you can use
class FooController < ApplicationController
protect_from_forgery except: :index
回答5:
Came across the same problem. Fixed it by adding to my controller:
skip_before_filter :verify_authenticity_token, if: :json_request?
回答6:
Did you try?
protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format.json? }
回答7:
This official doc - talks about how to turn off forgery protection for api properly http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
回答8:
This is a security feature in Rails. Add this line of code in the form:
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Documentation can be found here: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
回答9:
These features were added for security and forgery protection purposes.
However, to answer your question, here are some inputs.
You can add these lines after your the controller name.
Like so,
class NameController < ApplicationController
skip_before_action :verify_authenticity_token
Here are some lines for different versions of rails.
Rails 3
skip_before_filter :verify_authenticity_token
Rails 4:
skip_before_action :verify_authenticity_token
Should you intend to disable this security feature for all controller routines, you can change the value of protect_from_forgery to :null_session on your application_controller.rb file.
Like so,
class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session
end
回答10:
If you're using jQuery with rails, be wary of allowing entry to methods without verifying the authenticity token.
jquery-ujs can manage the tokens for you
You should have it already as part of the jquery-rails gem, but you might need to include it in application.js with
//= require jquery_ujs
That's all you need - your ajax call should now work
For more information, see: https://github.com/rails/jquery-ujs
回答11:
Add authenticity_token: true
to the form tag
回答12:
When you define you own html form then you have to include authentication token string ,that should be sent to controller for security reasons. If you use rails form helper to generate the authenticity token is added to form as follow.
<form accept-charset="UTF-8" action="/login/signin" method="post">
<div style="display:none">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
</div>
...
</form>
So the solution to the problem is either to add authenticity_token field or use rails form helpers rather then compromising security etc.
回答13:
All my tests were working fine. But for some reason I had set my environment variable to non-test:
export RAILS_ENV=something_non_test
I forgot to unset this variable because of which I started getting ActionController::InvalidAuthenticityToken
exception.
After unsetting $RAILS_ENV
, my tests started working again.
来源:https://stackoverflow.com/questions/16258911/rails-4-authenticity-token