Question

i am reading about Rack::Throttle and i want to change the default client identifier from an IP to somethng else. The documentation says it can be done

The rate-limiting counters stored and maintained by Rack::Throttle are keyed to unique HTTP clients.

By default, HTTP clients are uniquely identified by their IP address as returned by Rack::Request#ip. If you wish to instead use a more granular, application-specific identifier such as a session key or a user account name, you need only subclass a throttling strategy implementation and override the #client_identifier method.

I have no clue where to add that in, here is my current subclass for another method. Does anybody know how to do this? https://github.com/datagraph/rack-throttle

    module Rack
  module Throttle
    class DailyRequests < Daily
      def allowed?(request)
        ## Insert rules
        super request
      end
    end

    class HourlyRequests < Hourly
      def allowed?(request)
        ## Insert rules
        super request
      end
    end

    class RequestInterval < Interval
      def allowed?(request)
        ## Insert rules
        super request
      end
    end
  end
end
Was it helpful?

Solution

You should subclass one of the existing rack-throttle classes (probably either Rack::Throttle::Interval or Rack::Throttle::TimeWindow, whichever one more closely aligns with your needs) and override the #client_identifier method.

#client_identifier is passed one argument, request, which is a Rack::Request instance containing information passed in the incoming HTTP request and can be used to get information such as HTTP headers, cookies, path, and possibly other info depending on your app. The default implementation looks like this:

# @param  [Rack::Request] request
# @return [String]
def client_identifier(request)
  request.ip.to_s
end

Here's an example of subclassing Rack::Throttle::Interval to match requests on a query parameter such as ?user_id=<id>:

class UserThrottle < Rack::Throttle::Interval
  def client_identifier(request)
    request['user_id']
  end
end

which you could use in a Rack application with:

use UserThrottle, :min => 100

Notice you can still pass options like :min to the Rack use statement, since it is just subclassing the existing throttle classes. And adopting this in a Rails app would just involve calling use in your application.rb file (see Rails on Rack).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top