Ruby on rails 是否在注册页面前添加条件?

Ruby on rails 是否在注册页面前添加条件?,ruby-on-rails,devise,Ruby On Rails,Devise,我想问用户一个问题,只有当用户正确回答我的问题时,才允许他注册。我找过了,但我的箱子好像不在那里 有没有一种惯用的方法来处理这种情况 第一个想法可能是使用javascript,但答案存储在LDAP中,我希望在rails中处理这个问题会更容易 我还考虑禁用/users/sign\u路由,手动调用操作(design/registration\new)并呈现视图(design/registration/new) 我可以想到的另一种方法是运行后台守护程序,它将收集会话id,用户在其中正确回答了问题。回答

我想问用户一个问题,只有当用户正确回答我的问题时,才允许他注册。我找过了,但我的箱子好像不在那里

有没有一种惯用的方法来处理这种情况

第一个想法可能是使用javascript,但答案存储在LDAP中,我希望在rails中处理这个问题会更容易

我还考虑禁用
/users/sign\u
路由,手动调用操作(
design/registration\new
)并呈现视图(
design/registration/new


我可以想到的另一种方法是运行后台守护程序,它将收集会话id,用户在其中正确回答了问题。回答正确后,用户将被重定向到公开可用的注册页面,该页面将通过守护进程获取检查用户会话id。

假设您已签署cookie数据(如Rails 3中的默认值),您可以按照您所说的做并使用会话:

# app/controllers/preauth_controller.rb
def new
end

def create
  if params[:answer] == 'correct answer'
    session[:preauthorized] = true
    redirect_to sign_up_path
  end
  flash[:error] = 'Incorrect answer'
  render :new
end


# app/controllers/users_controller.rb
before_filter :verify_preauth, only: [:new, :create]

def verify_preauth
  redirect_to new_preauth_path unless session[:preauthorized]
end
但是,如果cookie数据没有签名,则
预授权的
密钥可能会被客户端篡改,因此不应被信任


如果您的页面在传输过程中通过TLS使用HTTPS进行加密,并且您没有任何XSS漏洞,那么这应该足以满足您的需要。如果您觉得这是一段特别敏感的代码,那么您需要的不仅仅是StackOverflow用户传递的想法,而是指导和实现一种全面的方法来保护您的应用程序

我有一点不同的方法

  • 展示问题,接收回答并验证
  • 设置加密会话
  • 使用此选项覆盖设备的注册控制器,这样即使他们直接访问url并尝试注册,也无法访问

    #app/controllers/registration_controller.rb
    class RegistrationsController < Devise::RegistrationsController
     before_filter :check_answered_or_not,only:[:create,:new]
      def check_answered_or_not
       if not session[:answered]==true
          redirect_to question_path
       end
      end
      private
      def sign_up_params
        params.require(:user).permit(:name,:phone,:password,:password_confirmation,:email)
      end
      def account_update_params
         params.require(:user).permit(:name,:phone,:password,:password_confirmation,:email,:current_password)
     end
    end
    
    #app/controllers/registration_controller.rb
    类注册控制器<设计::注册控制器
    筛选前:选中或不选中:[:创建,:新建]
    def检查是否回答
    如果不是会话[:应答]==真
    重定向到问题路径
    结束
    结束
    私有的
    def注册参数
    参数要求(:用户)。允许(:姓名,:电话,:密码,:密码确认,:电子邮件)
    结束
    def帐户更新参数
    参数要求(:用户).允许(:姓名,:电话,:密码,:密码确认,:电子邮件,:当前密码)
    结束
    结束
    

  • 我的两个孩子所以。。。可能它应该在
    模块中可验证

  • 使用此命令生成Validatables控制器
  • 自定义此控制器,如下所示: (您可以看到此模块的代码)

  • 这不是符合要求的解决方案,但我希望它能帮助您……

    我认为最简单的方法是将默认的Desive controller更改为自定义的Desive controller,其中包含
    ,然后再执行操作

    # routes.rb
    devise_for :users, :controllers => {:registrations => "registrations"}
    
    通过以下控制器实现:

    # app/controllers/registrations_controller.rb
    class RegistrationsController < Devise::RegistrationsController
      before_action :check_answers, only: :new # :new action is responsible for :sign_up route
    
      private
    
      def check_answers
        unless session[:gave_answers]
          redirect_to ask_questions_path
          false
        end
      end
    end 
    
    一旦此控制器继承自
    designe::RegistrationsController
    所有行为都保持默认状态,但检查答案功能除外

    关于您关于惯用方式的问题,请参阅。你的应用程序-你的逻辑,没问题

    更新:


    在评论中@bbozo用这个和其他答案指出了某些安全问题。为了使其更安全,您可以添加并设置一些随机的秘密令牌(更多信息请参见评论)。

    为了提高先前建议的安全性,最好的建议似乎是coreyward提供的,但它是不安全的(无论cookie是否加密-请参阅我在OP上的评论)

    可选择做/玩的事情

  • 创建用户时删除成功使用的
    Rails.cache
    条目
  • :expires\u在
    设置中如果你愿意,你通常希望它尽可能短,尽可能长:)但是rails默认的15分钟是相当不错的
  • 有更好的方法解决Cookie的这一问题和类似的安全问题-即您可以创建一个
    server\u session
    对象,该对象基本上与
    session
    相同,但将数据存储在
    Rails.cache
    中,并在
    session
    中存储一个随机过期令牌,用于访问缓存项就像我们在这里做的一样
  • 只需转到服务器端会话,不必担心会话安全性,但这意味着由于您的
    Rails.cache
    往返(redis、memcache、AR等)而需要更长的响应时间
  • 如果需要安全地存储在主机上的更多数据,可以将值散列存储到缓存值中,而不是
    OK

  • 如果您需要假设cookie数据是加密的,那么您就错了。Cookie数据在Rails中多年没有被加密,不是因为它在技术上很困难,而是因为担心程序员可能会使用它来保护客户端上的数据,这是一个坏消息practice@bbozo“恐惧”关于加密cookie数据,新手开发人员不会理解加密cookie仍然存在的安全问题,即劫持/固定和重放。我已经更新了我的答案,以反映加密实际上是不必要的,而且,代码将与Rails 3的签名cookies一样安全。还有一个事实,如果你不在cookie中添加额外的数据,它将允许任何人访问系统注册:不应该信任Pokiokcookcookie来保留客户端或中间人不愿意解密/伪造的数据。还考虑拥有一个被窃取的cookie,使用<代码>回答= true将导致立即和可重复的注册任何拥有Cookie的人的能力,您不能相信<代码>会话<代码>,以保持允许访问某人的会计会话的数据总是用来保持当前用户ID和数据关联。当前会话,这就是为什么窃取用户的cookies会让攻击者根据受害者的姓名进行操作。引用Rails指南:“因此,cookie充当临时身份验证
    # app/controllers/registrations_controller.rb
    class RegistrationsController < Devise::RegistrationsController
      before_action :check_answers, only: :new # :new action is responsible for :sign_up route
    
      private
    
      def check_answers
        unless session[:gave_answers]
          redirect_to ask_questions_path
          false
        end
      end
    end 
    
    # somewhere in questions controller:
    if answers_correct?
      session[:gave_answers] = true
      redirect_to new_registration_path
    end
    
    # app/controllers/preauth_controller.rb
    def new
    end
    
    def create
      if params[:answer] == 'correct answer'
        # Create a secret value, the `token`, we will share it to the client
        # through the `session` and store it on the server in `Rails.cache`
        # (or you can use the database if you like)
        #
        # The fact that this token expires (by default) in 15 minutes is
        # a bonus, it will secure the system against later use of a stolen
        # cookie. The token is also secure against brute force attack
        @token = SecureRandom.base64
        session[:preauthorization_token] = @token
        Rails.cache.write("users/preauthorization_tokens/#{@token}", "OK")
        redirect_to sign_up_path
      else
        flash[:error] = 'Incorrect answer'
        render :new
      end
    end
    
    
    # app/controllers/users_controller.rb
    before_filter :verify_preauth, only: [:new, :create]
    
    def verify_preauth
      # When we approve preauthorization we confirm that the
      # `token` is known to the client, if the client knows the token
      # let him sign up, else make him go away
      token = session[:preauthorization_token]
      redirect_to new_preauth_path unless token and Rails.cache.read("users/preauthorization_tokens/#{token}") == "OK"
    end