我的回答大量借鉴了@Jimbo 和@Sija,但是我使用的是Rails CSRF Protection + Angular.js 建议的设计/angularjs 约定:protect_from_forgery 让我在 POST 上注销,并在我的博客上详细说明了一点原来是这样做的。这在应用程序控制器上有一个为 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 清理的一部分,其他人可能会对此感兴趣。博客文章在这里,其他更改包括:
从 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 操作的请求。