Skip to content
This repository has been archived by the owner on Jul 25, 2024. It is now read-only.

Commit

Permalink
api: add custom throttling class
Browse files Browse the repository at this point in the history
This class is based of UserRateThrottle from DRF with a little change
to only throttle social account users.

It does use standard DRF throttling settings, so to make use of that just do:

```
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': ['squad.api.SocialUserRateThrottle'],
	'DEFAULT_THROTTLE_RATES': {
            'socialuser': '5/h',
	}
    }
```

Note the 'socialuser' part, it is necessary for the thottling work properly.

Signed-off-by: Charles Oliveira <[email protected]>
  • Loading branch information
chaws committed Apr 5, 2024
1 parent 9b0cb10 commit 71e86da
Showing 1 changed file with 40 additions and 0 deletions.
40 changes: 40 additions & 0 deletions squad/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from django.core.cache import cache
from rest_framework.throttling import UserRateThrottle


class SocialUserRateThrottle(UserRateThrottle):
"""
Limits the rate of API calls that may be made by a given social user.
The user id will be used as a unique cache key if the user is
authenticated. For anonymous requests, the IP address of the request will
be used.
"""

scope = "socialuser"

def is_social_user(self, user):
"""
Social account user might use multiple applications (github, gitlab, google, ...)
to log in. But all of the login applications would likely point to the same
django user, which is what we want to rate limit here.
"""

key = f"socialuser#{user.id}"
from allauth.socialaccount.models import SocialAccount
return cache.get_or_set(key, SocialAccount.objects.filter(user_id=user.id).exists())

def get_cache_key(self, request, view):
if request.user and request.user.is_authenticated:
if not self.is_social_user(request.user):
# do not throttle non-social users
return None

ident = request.user.pk
else:
ident = self.get_ident(request)

return self.cache_format % {
"scope": self.scope,
"ident": ident
}

0 comments on commit 71e86da

Please sign in to comment.