在条件前面添加条件?

Ado*_*obe 14 ruby-on-rails devise

我想问用户一个问题,并且只有在用户正确回答我的问题时才让他注册.我搜索了如何设法,但我的情况似乎并不存在.

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

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

我还在考虑禁用/users/sign_up路由,devise/registration#new手动调用action()并渲染视图(devise/registration/new).

我能想到的另一种方法是运行一个后台守护进程,它将收集会话ID,用户可以正确回答问题.在正确答案中,用户将被重定向到公共可用的注册页面,该页面将使用守护程序检查用户的会话ID.

cor*_*ard 6

假设您已经签署了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
Run Code Online (Sandbox Code Playgroud)

但是,如果cookie数据未签名,则preauthorized密钥可能被客户端篡改,因此不应被信任.

如果您的页面在传输过程中使用HTTPS通过TLS加密,并且您没有任何XSS漏洞,那么这应该足够安全以满足您的需求.如果您认为这是一段特别敏感的代码,那么您需要的不仅仅是StackOverflow用户的想法,而是指导和实施保护应用程序安全的综合方法.


bbo*_*ozo 4

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

# 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
Run Code Online (Sandbox Code Playgroud)

可选的事情做/玩......

  1. Rails.cache创建用户时删除成功使用的条目
  2. 如果你愿意,可以随意:expires_in设置,通常你希望它尽可能短,并且根据需要长:),但 Rails 默认的 15 分钟非常好
  3. 有更好的方法来解决这个问题以及类似的 cookie 安全问题 - 也就是说,您可以创建一个server_session对象,其功能与 Cookie 基本相同,但使用随机的可过期令牌session存储数据,该令牌存储在用于以大致相同的方式访问缓存条目我们在这里做Rails.cachesession
  4. 只需转到服务器端会话,不用担心会话安全性,但这意味着由于往返Rails.cache(redis、memcache、AR...)而导致响应时间更长
  5. 如果OK您需要更多安全存储在主机上的数据来解决此问题,您可以存储值的哈希值,而不是存储到缓存值中
  6. ...