我的回答大量借鉴了@Jimbo 和@Sija,但是我使用的是Rails CSRF Protection + Angular.js: protect_from_forgery makes me to log out on POST 建议的devise/angularjs 约定,并在我最初这样做时对我的blog 进行了一些详细说明。这在应用程序控制器上有一个方法来为 csrf 设置 cookie:
after_filter :set_csrf_cookie_for_ng
def set_csrf_cookie_for_ng
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
end
所以我使用@Sija 的格式,但使用早期 SO 解决方案中的代码,给我:
class SessionsController < Devise::SessionsController
after_filter :set_csrf_headers, only: [:create, :destroy]
protected
def set_csrf_headers
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
end
end
为了完整起见,由于我花了几分钟的时间来解决它,我还注意到需要修改您的 config/routes.rb 以声明您已覆盖会话控制器。比如:
devise_for :users, :controllers => {sessions: 'sessions'}
这也是我在我的应用程序上完成的大型 CSRF 清理的一部分,其他人可能会对此感兴趣。 blog post is here,其他变化包括:
从 ActionController::InvalidAuthenticityToken 中救援,这意味着如果事情不同步,应用程序将自行修复,而不是用户需要清除 cookie。在 Rails 中,我认为您的应用程序控制器将默认为:
protect_from_forgery with: :exception
在这种情况下,您需要:
rescue_from ActionController::InvalidAuthenticityToken do |exception|
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
render :error => 'invalid token', {:status => :unprocessable_entity}
end
我也对竞态条件以及与 Devise 中的可超时模块的一些交互感到悲伤,我在博文中对此进行了进一步评论 - 简而言之,您应该考虑使用 active_record_store 而不是 cookie_store,并且要小心关于在 sign_in 和 sign_out 操作附近发出并行请求。