Ruby on Rails:表单提交时“您想要的更改被拒绝”

dev*_*leo 4 ruby authentication ruby-on-rails

ruby 3.0.1 rails 6.1.2 'devise', '~> 4.7', '>= 4.7.3'

我的处境非常不寻常。我正在将 Rails 安装从一台服务器迁移到另一台服务器。我相信我已经完成了大约 95%,刚刚恢复了生产数据库。

但是,任何涉及表单提交的操作(包括用户注册和登录)都会显示错误页面:

The change you wanted was rejected.

Maybe you tried to change something you didn't have access to.
Run Code Online (Sandbox Code Playgroud)

服务器日志给了我一些更有用的东西:

Completed 422 Unprocessable Entity in 2ms (Allocations: 433)
FATAL -- ActionController::InvalidAuthenticityToken
Run Code Online (Sandbox Code Playgroud)

这让我很困惑。因为我确实重新生成了master.key和credentials.yml.enc,并通过环境变量使master.key的内容可用RAILS_MASTER_KEY。这意味着表单具有适当的<input type="hidden" name="authenticity_token" value="<removed for stack_overflow>">包含功能以防止跨站点脚本攻击。

我认为这与会话没有任何关系,因为甚至用户注册也会受此影响。我正在使用 Devise 进行身份验证。

但是……现在我碰壁了。从这里无处可去。有谁知道出了什么问题吗?

更新1

添加skip_before_action :verify_authenticity_token确实让我跳过了这个问题。我对此解决方案感到不满意。

更新2

我有这些元标签。

<%= csrf_meta_tags %>
<%= csp_meta_tag %>
Run Code Online (Sandbox Code Playgroud)

dev*_*leo 5

我羞于承认这一点。但是nginx没有正确配置。一旦我到达了 Rails 的临界点,我终于开始问这怎么可能发生。

事情是这样的。在内部,rails 使用 http 来访问各种端点。我有一个 nginx 重定向块,如下所示:

 server {
  listen 80 default_server;

  server_name _;

  return 301 https://$host$request_uri;
}
Run Code Online (Sandbox Code Playgroud)

这意味着每次在 http 上访问内部端点时,它都会变成带有 301... 的 https,而 301 始终是 GET。一旦我使用config.force_ssl = trueproduction.rb,我只需要重做我的 ngix 配置来支持它。

这是工作配置。

location / {
  proxy_set_header Host $http_host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto https;
  proxy_redirect off;
  proxy_pass http://app:3000;
}
Run Code Online (Sandbox Code Playgroud)

它看起来像身份验证令牌问题的原因是,一旦请求作为 GET 发送,它就成为不可处理的实体。尽管我可以在浏览器检查中看到它,但当它到达那里时,令牌可能为零或其他东西。只是动词用错了。