Rails 4.2在ActionController :: InvalidAuthenticityToken中升级到5个结果

时间:2017-07-10 00:26:14

标签: ruby-on-rails devise csrf-protection

所以我有一个完全正常工作的4.2 Rails应用程序,我使用devise进行电子邮件登录,并为Oauth完全设计无关的omniauth流程。

我决定更新到Rails 5.1.2,并获得了可怕的CSRF InvalidAuthenticityToken。尝试通过设计(电子邮件)或使用omniauth登录时会发生这种情况。

Environment: Development


application_controller.rb

  protect_from_forgery with: :exception, prepend: true

...

  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name])
    devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :last_name])
  end

  def after_sign_in_path_for(resource)
    user_path(id: resource.id)
  end

会话控制器没有任何相关性,没有before_过滤器,没有特定的方法。

 Started POST "/users/sign_in" for 127.0.0.1 at 2017-07-09 22:32:25 -0100
Processing by Users::SessionsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"eTJnjnTDNbahT+W8ajr9fH8tGSC0wfismuNbwr0qtQkYoCoFqDm5kZ+nlwAnz+RbLL4v41oqgmqJzaIVJYWxXw==", "user"=>{"email"=>"*****@gmail.com", "password"=>"[FILTERED]"}, "commit"=>"log in"}
Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity in 2ms (ActiveRecord: 0.0ms)



ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

actionpack (5.1.2) lib/action_controller/metal/request_forgery_protection.rb:195:in `handle_unverified_request'

使用CSRF标题呈现html:

<meta name="csrf-param" content="authenticity_token">
<meta name="csrf-token" content="eTJnjnTDNbahT+W8ajr9fH8tGSC0wfismuNbwr0qtQkYoCoFqDm5kZ+nlwAnz+RbLL4v41oqgmqJzaIVJYWxXw==">

在表格上:

<input type="hidden" name="authenticity_token" value="eTJnjnTDNbahT+W8ajr9fH8tGSC0wfismuNbwr0qtQkYoCoFqDm5kZ+nlwAnz+RbLL4v41oqgmqJzaIVJYWxXw==">

尝试通过omniauth时:

Started GET "/auth/linkedin" for 127.0.0.1 at 2017-07-09 23:10:47 -0100
I, [2017-07-09T23:10:47.726334 #33989]  INFO -- omniauth: (linkedin) Request phase initiated.
Started GET "/auth/linkedin/callback?code=AQTYEqh7Ly5soZIFs_XfERBDL-EzRb-q_tkJgIIpLZWhlpcNLG6Ib9dQg2_74gRjDquZp_B3zTXjaBgpoRnJgbVoyVyMad0Ft8kjyMkTdhxPgWO5jbA&state=7f63139d28f961f32c789d07cc7ddfb6cd7c09b26af91733" for 127.0.0.1 at 2017-07-09 23:10:48 -0100
I, [2017-07-09T23:10:48.980311 #33989]  INFO -- omniauth: (linkedin) Callback phase initiated.
E, [2017-07-09T23:10:48.980683 #33989] ERROR -- omniauth: (linkedin) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected
E, [2017-07-09T23:10:48.981033 #33989] ERROR -- omniauth: (linkedin) Authentication failure! invalid_credentials: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected

OmniAuth::Strategies::OAuth2::CallbackError (csrf_detected | CSRF detected):

我已经尝试过:

protect_from_forgery with: :exception, prepend: false(&amp; true)

config/secrets.yml中的硬编码:

development:
  secret_key_base: 0beec021fbe866716933a1da494be36f21bb6cf446ab7d315eb129706931bb2b284aa8e5507d0ab829abb8c2155958b47500aeadd5eace9cdc27643121cf6adf

&amp;尝试用:

secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>

以及Env变量

我之前在config/environment.rb上使用了这个:

# Load the Rails application.
require_relative 'application'
# Load the app's custom environment variables here, before environments/*.rb
app_env_vars = File.join(Rails.root, 'config', 'initializers', 'app_env_vars.rb')
secret = File.join(Rails.root, 'config', 'initializers', 'secret_token.rb')
load(app_env_vars) if File.exists?(app_env_vars)
load(secret) if File.exists?(secret)

# Initialize the Rails application.
Rails.application.initialize!

在没有它的情况下尝试,并将该文件中定义的所有环境变量传递给bash_profile终端加载。

所以基本上我没有想法,如果你有任何想法,请分享,谢谢

4 个答案:

答案 0 :(得分:0)

您是否尝试过将之前的操作放在protect_from_forgery之前并将prepend设置为false?所以你的应用程序控制器看起来像这样:

 before_action :configure_permitted_parameters, if: :devise_controller?
 protect_from_forgery with: :exception, prepend: false

 protected

 def configure_permitted_parameters
   devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, 
   :last_name])
   devise_parameter_sanitizer.permit(:account_update, keys: 
   [:first_name, 
   :last_name])
 end

 def after_sign_in_path_for(resource)
   user_path(id: resource.id)
 end

或者您可以尝试执行的操作是在before_action中对用户进行身份验证,因为您正在使用oauth,如下面的代码所示,从此博客中获取从rails 4切换到rails 5,随时阅读它。 (http://blog.bigbinary.com/2016/04/06/rails-5-default-protect-from-forgery-prepend-false.html

 class ApplicationController < ActionController::Base
 before_action :authenticate
 protect_from_forgery unless: -> { @authenticated_by.oauth? }

 private
 def authenticate
   if oauth_request?
     # authenticate with oauth
     @authenticated_by = 'oauth'.inquiry
   else
     # authenticate with cookies
     @authenticated_by = 'cookie'.inquiry
   end
 end
end

希望其中一个答案可以帮助你。

答案 1 :(得分:0)

I wasn't able to pinpoint the problem. Effectively I just created a fresh rails 5 application with everything the same, copied everything over and it worked from the get go.

答案 2 :(得分:0)

首先,我建议逐步更新应用程序,即最新的补丁版本,暂时为4.2.9。确保它仍然有效并且测试套件是绿色的:)然后您就可以将应用更新到5.0.4了。每次升级主要版本或次要版本时,请记住运行rake rails:update(Rails 5.0+以上的rails app:update)以更新配置和其他一些最初生成的文件。这是指向Rails guide on upgrading from Rails 4.2 to Rails 5.0的链接。

答案 3 :(得分:0)

当前从Rails 4.2升级到5.0时,正在更新旧的Rails + devise应用,并遇到了类似的问题。

导致呼叫顺序是罪魁祸首:

  before_action :authenticate_user!

  protect_from_forgery with: :exception

在rails 4.2中工作,而在5.0中,您需要先调用protect_from_forgery

  protect_from_forgery with: :exception

  before_action :authenticate_user!