我是 Rails 的新手,在 protect_from_forgery 的概念上遇到了困难,据我所知,此方法使用 :verify_authenticity_token 来保护路由。我使用它的路线是一条 API 路线;像这样:
class ApiController < ActionController::API
protect_from_forgery with: :null, only: %i[execute]
before_action :validate_csrf_token, only: %i[execute]
def execute
# action here
end
private
def validate_csrf_token
return true unless request.post?
token = request.headers['X-CSRF-Token']
if token.blank? || !valid_authenticity_token?(token, nil)
render json: { error: 'Invalid CSRF token' }, status: :unprocessable_entity
end
end
end
我还有另一个控制器,用于从我的 Rails 应用程序获取令牌
class CsrfTokenController < ApplicationController
skip_before_action :verify_authenticity_token
def index
render json: { csrf_token: form_authenticity_token }
end
end
我发送到我的 ApiController。我遇到的第一个问题是这个错误
HTTP Origin header (http://localhost:3020) didn't match request.base_url (http://localhost:3000)
其次,当我执行发布请求时,我发送的令牌无效
error: "Invalid CSRF token"
我可以确认令牌请求是我打印变量时发回的请求。
我在这里遗漏了什么,还是我理解 :null_session 完全错了?
编辑:
由于提到保护路线的方法不正确而更新
CSRF 保护的作用是让您在一定程度上确定请求来自您自己的服务器呈现的页面。这对于旨在为您自己的单页应用程序提供 JSON 的经典应用程序和 API 非常有用。但是,如果您正在创建一个旨在跨域使用并且也可能由基于服务器的客户端使用的 API,那么 Rails CSRF 保护是无关紧要的,实际上完全反对这些要求。
方法使用 form_authenticity_token 来保护路由
不不不。其工作方式是将唯一令牌呈现到页面的 HTML(表单和元标记)中,并将相同的令牌存储在会话中。
由于会话存储在加密的 cookie 中,我们可以合理地确定它没有被篡改。
当用户随后提交表单时,您的控制器会检查请求正文或
X-CSRF-Token
标头中的令牌,并引发异常,除非它与会话 cookie 提供的值匹配。此令牌应仅在单个请求周期内有效。
由于默认情况下 cookie 是单个域,因此当您从不同来源发送请求时,您实际上不应该期望它起作用。
参见: