所以我有一个完全正常工作的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终端加载。
所以基本上我没有想法,如果你有任何想法,请分享,谢谢
答案 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!