Ruby on rails 轨道/设计登录系统&x27;t在Safari上工作(422/CSRF错误)

Ruby on rails 轨道/设计登录系统&x27;t在Safari上工作(422/CSRF错误),ruby-on-rails,devise,safari,csrf,Ruby On Rails,Devise,Safari,Csrf,登录在Chrome上运行良好,但在Safari上不起作用(或者我假设其他Webkit浏览器)。您登录后,我收到此错误消息(“您想要的更改被拒绝。可能您试图更改您无权访问的内容。”): 根据我的heroku日志,发生了这样的事情: 2016-12-07T14:14:23.778153+00:00 app[web.1]: Can't verify CSRF token authenticity 2016-12-07T14:14:23.778899+00:00 app[web.1]: Complet

登录在Chrome上运行良好,但在Safari上不起作用(或者我假设其他Webkit浏览器)。您登录后,我收到此错误消息(“您想要的更改被拒绝。可能您试图更改您无权访问的内容。”):

根据我的heroku日志,发生了这样的事情:

2016-12-07T14:14:23.778153+00:00 app[web.1]: Can't verify CSRF token authenticity
2016-12-07T14:14:23.778899+00:00 app[web.1]: Completed 422 Unprocessable Entity in 2ms (ActiveRecord: 0.0ms)
2016-12-07T14:14:23.785544+00:00 app[web.1]:
2016-12-07T14:14:23.785547+00:00 app[web.1]: ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
我相信我正在发送正确的CSRF令牌,但似乎出现了故障。这是我当前的
应用程序\u控制器。rb

class ApplicationController < ActionController::Base


  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  after_action :flash_to_headers

  # this is so that json requests don't redirect without a user
  before_action :authenticate_user!
  # before_action :authenticate_user!, unless: request.format == :json
  # before_action :user_needed, if: request.format == :json

  before_action :set_paper_trail_whodunnit
  before_action :set_global_search_variable


  def set_global_search_variable
    @q = Person.ransack(params[:q])
  end

  def user_needed
    unless current_user
      render json: { 'error' => 'authentication error' }, status: 401
    end
  end



  def flash_to_headers
    return unless request.xhr?
    response.headers['X-Message'] = flash_message if flash_message
    response.headers['X-Message-Type'] = flash_type.to_s if flash_type
    flash.discard # don't want the flash to appear when you reload page
  end

  private

    def flash_message
      [:error, :warning, :notice].each do |type|
        return flash[type] unless flash[type].blank?
      end
      nil
    end

    def flash_type
      [:error, :warning, :notice].each do |type|
        return type unless flash[type].blank?
      end
      nil
    end
class ApplicationController'authentication error'},状态:401
结束
结束
def flash_至_标题
除非请求否则返回。xhr?
response.headers['X-Message']=如果是flash\u消息,则为flash\u消息
response.headers['X-Message-Type']=flash\u Type.to\u s if flash\u Type
flash.discard#不希望在重新加载页面时显示flash
结束
私有的
def flash_信息
[:错误,:警告,:注意]。每个do |类型|
返回flash[type],除非flash[type]。是否为空?
结束
无
结束
def闪蒸型
[:错误,:警告,:注意]。每个do |类型|
返回类型,除非闪烁[type]。是否为空?
结束
无
结束
(将
protect_from_force with:
更改为
null_session
只会导致无休止地返回登录屏幕。)

参考了一个类似的问题,但没有讨论设计的复杂性。据说Desive已经处理了这个问题,但不知何故它在这里不起作用。他们中的许多人已经年迈,所以我不确定他们今天会有多重要

我也尝试过在实际的Desive Github repo中搜索bug,但这些线程中的建议似乎没有任何效果。有很多关于编辑应用程序控制器的建议,但很多时候这似乎会使整个应用程序崩溃

该应用程序运行Ruby 2.2.5和Rails 4.2.7.1。更新到Rails 5是否有助于解决此问题

它也有一个现有的(可能是黑客)覆盖使管理员帐户;该人员通过designe注册,然后通过
pqsl
shell中另一个名为
approved
的字段手动获得管理员权限。我不确定这是否有关系

该应用程序位于Github上,供任何想要查看的人使用:

事实证明,我的问题已由解决。它毕竟不在应用程序控制器中,而是在
config/initializers/session\u store.rb

这是我最初的
会话\u存储

Logan::Application.config.session_存储:cookie_存储,密钥:''u cutgroup_session',安全:(Rails.env.production?| | Rails.env.staging?)

在进一步研究后,我发现了以下建议:

Rails.application.config.session\u存储:cookie\u存储,键:“\Rails\u会话{Rails.env}”,域:all

这仍然不起作用;但是,它会在日志中显示401错误(而不是422),并重定向回登录页面,而不是显示上面我截屏显示的错误屏幕

最后,我从
Rails.application.config.session\u store:cookie\u store的末尾删除了
domain:all
部分,键:“\u Rails\u session\uuuu{Rails.env}”
在Safari上对我有效(浏览器在任何时候都不会阻止cookie)。现在,当项目部署到Heroku上时,我就可以登录了

悬赏是一个沉重的代价,但至少评论员帮助我澄清了我的想法并找到了解决办法!如果其他人遇到了这个问题,并提出了一个更好的问题,我会投赞成票,但我想我现在已经知道了。

试试:

控制器/应用程序.rb

protect_from_forgery with: :null_session
class Users::SessionsController < Devise::SessionsController
skip_before_filter :verify_authenticity_token, :only => [:destroy]
end
及 覆盖您的设备控制器

会话\u controller.rb

protect_from_forgery with: :null_session
class Users::SessionsController < Devise::SessionsController
skip_before_filter :verify_authenticity_token, :only => [:destroy]
end
class用户::sessioncontroller[:destroy]
结束

before\u action:authenticate\u user!@AlexanderLuna在哪里可以找到该方法?应用程序控制器的这一部分是\u action:authenticate\u user!之前的
的唯一实例,尽管有几个
在\u操作之前跳过\u:验证\u用户项目中的实例。我无法告诉您它在哪里。你必须知道,因为你把它放在那里了。我之所以这么问是因为它每次都会在你的控制器收到请求之前被调用。我理解。我不是自己从头开始创建这个项目的,所以我不确定它在哪里,尽管这个项目使用Desive进行用户注册和身份验证。我在谷歌上找不到一个例子。似乎引用了较旧的版本,因为我在
lib
中没有
designe
子文件夹,也没有
helpers.rb
文件。我在safari上遇到了同样的CSRF令牌问题。已在我的浏览器中禁用Cookie。。你确定Safari接受你应用程序中的cookies吗?谢谢回答!但是,我听说将应用程序控制器中的设置更改为
:null\u session
是不明智的,因为这将允许伪造并覆盖保护。它对我来说也不起作用(尽管没有按照这里的规定覆盖designe控制器),它的这一部分为我解决了一个相关问题:
key:“\u rails\u session{rails.env}”