Ruby-on-rails Rails 5 API 保护_从_伪造
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42795288/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rails 5 API protect_from_forgery
提问by lostphilosopher
I have a Rails 5 API app (ApplicationController < ActionController::API). The need came up to add a simple GUI form for one endpoint of this API.
我有一个 Rails 5 API 应用程序 ( ApplicationController < ActionController::API)。需要为这个 API 的一个端点添加一个简单的 GUI 表单。
Initially I was getting ActionView::Template::Error undefined method protect_against_forgery?when I tried to render the form. I added include ActionController::RequestForgeryProtectionand protect_from_forgery with:exceptionto that endpoint. Which solved that issue as expected.
最初我ActionView::Template::Error undefined method protect_against_forgery?尝试渲染表单时遇到了问题。我将include ActionController::RequestForgeryProtection和添加protect_from_forgery with:exception到该端点。哪个按预期解决了这个问题。
However, when I try to submit this form I get: 422Unprocessable EntityActionController::InvalidAuthenticityToken. I've added <%= csrf_meta_tags %>and verified that meta: csrf-paramand meta: csrf-tokenare present in my headers, and that authenticity_tokenis present in my form. (The tokens themselves are different from each other.)
但是,当我尝试提交此表单时,我得到:422Unprocessable EntityActionController::InvalidAuthenticityToken。我已经添加<%= csrf_meta_tags %>并验证了meta: csrf-param和meta: csrf-token存在于我的标题中,并且authenticity_token存在于我的表单中。(令牌本身彼此不同。)
I've tried, protect_from_forgery prepend: true, with:exception, no effect. I can "fix" this issue by commenting out: protect_from_forgery with:exception. But my understanding is that that is turning off CSRF protection on my form. (I want CSRF protection.)
我试过了protect_from_forgery prepend: true, with:exception,没有效果。我可以“修复”这个问题被注释掉:protect_from_forgery with:exception。但我的理解是,这会关闭我表单上的 CSRF 保护。(我想要 CSRF 保护。)
What am I missing?
我错过了什么?
UPDATE:
更新:
To try to make this clear, 99% of this app is a pure JSON RESTful API. The need came up to add one HTML view and form to this app. So for one ControllerI want to enable full CSRF protection. The rest of the app doesn't need CSRF and can remain unchanged.
为了弄清楚这一点,这个应用程序的 99% 是纯 JSON RESTful API。需要向这个应用程序添加一个 HTML 视图和表单。所以对于一个控制器,我想启用完整的 CSRF 保护。应用程序的其余部分不需要 CSRF,可以保持不变。
UPDATE 2:
更新 2:
I just compared the page source of this app's HTML form and Header with another conventional Rails 5 app I wrote. The authenticity_tokenin the Header and the authenticity_tokenin the form are the same. In the API app I'm having the problem with, they're different. Maybe that's something?
我只是将这个应用程序的 HTML 表单和页眉的页面源代码与我编写的另一个常规 Rails 5 应用程序进行了比较。的authenticity_token页眉和authenticity_token形式是相同的。在我遇到问题的 API 应用程序中,它们是不同的。也许那是什么?
UPDATE 3:
更新 3:
Ok, I don't the the mismatch is the issue. However, in further comparisons between the working and non-working apps I noticed that there's nothing in Network > Cookies. I see a bunch of things like _my_app-sessionin the cookies of the working app.
好吧,我不认为不匹配是问题所在。但是,在工作应用程序和非工作应用程序之间的进一步比较中,我注意到网络 > Cookies 中没有任何内容。我_my_app-session在工作应用程序的 cookie 中看到了很多东西。
回答by lostphilosopher
Here's what the issue was: Rails 5, when in API mode, logically doesn't include the Cookie middleware. Without it, there's no Session keystored in a Cookie to be used when validating the token I passed with my form.
这是问题所在:Rails 5 在 API 模式下,逻辑上不包括 Cookie 中间件。没有它,key在验证我通过表单传递的令牌时,不会使用 Cookie 中存储的 Session 。
Somewhat confusingly, changing things in config/initializers/session_store.rbhad no effect.
有点令人困惑的是,更改内容config/initializers/session_store.rb没有任何效果。
I eventually found the answer to that problem here: Adding cookie session store back to Rails API app, which led me here: https://github.com/rails/rails/pull/28009/fileswhich mentioned exactly the lines I needed to add to application.rb to get working Cookies back:
我最终在这里找到了这个问题的答案:将 cookie 会话存储添加回 Rails API 应用程序,这让我来到这里:https: //github.com/rails/rails/pull/28009/files,它准确地提到了我需要的行添加到 application.rb 以获取工作 Cookies:
config.session_store :cookie_store, key: "_YOUR_APP_session_#{Rails.env}"
config.middleware.use ActionDispatch::Cookies # Required for all session management
config.middleware.use ActionDispatch::Session::CookieStore, config.session_options
Those three lines coupled with:
这三行加上:
class FooController < ApplicationController
include ActionController::RequestForgeryProtection
protect_from_forgery with: :exception, unless: -> { request.format.json? }
...
And of course a form generated through the proper helpers:
当然还有通过适当的助手生成的表单:
form_tag(FOO_CREATE_path, method: :post)
...
Got me a CSRF protected form in the middle of my Rails API app.
在我的 Rails API 应用程序中间给了我一个受 CSRF 保护的表单。
回答by Ricky Brown
If you're using Rails 5 API mode, you do not use protect_from_forgeryor include <%= csrf_meta_tags %>in any view since your API is 'stateless'. If you were going to use full Rails (not API mode) while ALSO using it as a REST API for other apps/clients, then you could do something like this:
如果您使用 Rails 5 API 模式,则不要使用protect_from_forgery或包含<%= csrf_meta_tags %>在任何视图中,因为您的 API 是“无状态”的。如果您打算使用完整的 Rails(而不是 API 模式),同时还将其用作其他应用程序/客户端的 REST API,那么您可以执行以下操作:
protect_from_forgery unless: -> { request.format.json? }
So that protect_from_forgerywould be called when appropriate. But I see ActionController::APIin your code so it appears you're using API mode in which case you'd remove the method from your application controller altogether
所以protect_from_forgery会在适当的时候调用。但是我ActionController::API在您的代码中看到,因此您似乎正在使用 API 模式,在这种情况下,您将完全从应用程序控制器中删除该方法
回答by puneet18
No need of protect_from_forgery for AJAX calls and apis.
AJAX 调用和 api 不需要protect_from_forgery。
If you want to disable it for some action then
如果您想为某些操作禁用它,那么
protect_from_forgery except: ['action_name']
回答by Muktesh Kumar
class Api::ApiController < ApplicationController
skip_before_action :verify_authenticity_token
end
Use as above with rails 5
如上使用导轨 5

