【问题标题】:Does directly visiting a url have the same effect as navigating via a link?直接访问 url 是否与通过链接导航具有相同的效果?
【发布时间】:2025-12-14 01:15:01
【问题描述】:

我有一个记录用户ip地址的投票系统,用户只能投票一次。如果投票数组中包含用户的ip地址,那么投票链接将不会显示给用户:

show.html.erb

<% if !ip_array.include? request.remote_ip %>
  <%= link_to "Vote!", vote_user_path(@user) %>
<% else %>
  You've already voted!
<% end %>

users_controller.rb

def vote
  @user = User.find(params[:id])
  @user.votes = @user.votes + 1
  @user.save
end

但是用户不能直接去www.my_website.com/users/:id/vote 绕过这个吗?如果是这样,我该如何防止这种情况发生?

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 path routes


    【解决方案1】:

    防止它的方法是将验证放在控制器操作中,而不是在视图中(或除了视图之外)。

    before_action :ensure_not_voted
    
    def vote
      @user = User.find(params[:id])
      @user.votes = @user.votes + 1
      @user.save
    end
    
    protected
    
    def ensure_not_voted
      # perform the check and stop on failure
      # already_voted is a fake function, replace it with your real check
      if already_voted
        halt(403)
      end
    end
    

    【讨论】:

    • 我应该在哪里定义 already_voted?我没有网站实际用户的模型;我的用户模型指的是别的东西。
    • 您需要将if !ip_array.include? request.remote_ip 逻辑移动到控制器中。我不知道真正的代码是什么样子的,你的代码中没有足够的上下文来理解它。
    【解决方案2】:

    对于更简单的解决方案,您可以为每个用户添加一个会话令牌,并检查 ip 是否包含特定令牌,例如

    添加before_filter :auth, :only =&gt; [:vote]

    def vote
      @user = User.find(params[:id])
      @user.votes = @user.votes + 1
      @user.save
      session[:token] = request.remote_ip
    end
    
    
    private
    
      def auth
            @ip = session[:token].to_s
    
            if @ip != nil
                redirect_to :back
                flash[:notice] = "You have already voted"
                return false
            else
                return true
            end
      end
    

    用户可以删除cookie再次投票(很少有人可以),对于这种情况,您可以将ip保存在数据库中并检查它

    【讨论】:

      最近更新 更多