Intro
Standard Practice
-
Login Endpoint: Apply a stricter throttle, such as allowing only a limited number of attempts per minute or hour (e.g., 5 attempts per minute).
-
Signup Endpoint: You can also apply throttling here, but you might choose a more lenient rate depending on your user base and anticipated traffic (e.g., 10 signups per minute).
In your settings.py
, you might set it up like this:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle', # For anonymous users
'rest_framework.throttling.UserRateThrottle', # For authenticated users
],
'DEFAULT_THROTTLE_RATES': {
'anon': '5/minute', # For login attempts
'user': '1000/day', # For general authenticated user actions
},
}
Implementing throttling on public endpoints like login
and signup
is essential for securing your application against common attacks while maintaining a good user experience.
Built-in throlling vs
django-ratelimit package
Both django-ratelimit and Django's built-in throttling
(using Django Rest Framework's throttling) are used to control the rate at which requests are processed. However, they have different approaches and use cases. Here’s a breakdown of the core differences:
- Functionality: It allows you to apply rate limiting on specific views by decorating them. You can specify limits based on various criteria (e.g., IP address, user, etc.).
- Granularity: Offers more fine-grained control over rate limits for individual views.
- Configuration: Requires decorators to be applied to each view you want to limit.
- Flexibility: You can set different limits for different views easily.
- Built-in Support: Throttling is integrated into DRF and can be configured globally or on a per-view basis using class-based views.
- Rate Limiters: It provides several built-in classes like AnonRateThrottle and UserRateThrottle, which can be customized for different user types.
- Settings-Based: Throttling limits can be defined in the settings, making it easy to manage across your application.
- Middleware-like Behavior: Throttling operates at a middleware level, meaning it's applied automatically based on the defined rules.
Which One to Use?
Usedjango-ratelimit
if you need:
- More control over specific views or need to set different limits easily.
- Custom logic or more complex rate limiting scenarios.
Use DRF Throttling
if you prefer:
- A straightforward and integrated approach to limit requests across the entire API.
- A consistent and centralized configuration in your Django settings.
Conclusion
If you're building a DRF-based API, starting with DRF's built-in
throttling might be the easier and more cohesive choice. For more complex or specific rate limiting needs, django-ratelimit offers additional flexibility.
Configuration
In your settings.py
, configure the throttling classes. You can set global throttling rules here:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle', # For anonymous users
'rest_framework.throttling.UserRateThrottle', # For authenticated users
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day', # 100 requests per day for anonymous users
'user': '1000/day', # 1000 requests per day for authenticated users
},
}
You can apply throttling to specific views or viewsets using the throttle_classes
attribute. Here's an example:
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from rest_framework.throttling import UserRateThrottle, AnonRateThrottle
from .models import YourModel
from .serializers import YourModelSerializer
class YourModelViewSet(viewsets.ModelViewSet):
queryset = YourModel.objects.all()
serializer_class = YourModelSerializer
permission_classes = [IsAuthenticated]
throttle_classes = [UserRateThrottle] # Apply user throttling to this view
# For a different view with different throttling
class AnotherViewSet(viewsets.ModelViewSet):
queryset = YourModel.objects.all()
serializer_class = YourModelSerializer
throttle_classes = [AnonRateThrottle] # Apply anonymous throttling to this view
If you need custom throttling logic, you can create a custom throttle class. Here's an example:
from rest_framework.throttling import SimpleRateThrottle
class CustomRateThrottle(SimpleRateThrottle):
scope = 'custom_user'
def get_cache_key(self, request, view):
return request.user.username if request.user.is_authenticated else None
# Then, add your custom throttle class to settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'path.to.CustomRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'custom_user': '10/minute', # Example: 10 requests per minute
},
}