Skip to content

Commit 4d54a16

Browse files
committed
add rate limit
1 parent 5f7ba48 commit 4d54a16

File tree

5 files changed

+52
-2
lines changed

5 files changed

+52
-2
lines changed

myproject/settings.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
from pathlib import Path
33
from datetime import timedelta
4+
import sys
45

56
# Build paths inside the project like this: BASE_DIR / 'subdir'.
67
BASE_DIR = Path(__file__).resolve().parent.parent
@@ -128,6 +129,15 @@
128129
'DEFAULT_AUTHENTICATION_CLASSES': (
129130
'rest_framework_simplejwt.authentication.JWTAuthentication',
130131
),
132+
"DEFAULT_THROTTLE_CLASSES": [
133+
"rest_framework.throttling.AnonRateThrottle",
134+
"rest_framework.throttling.UserRateThrottle",
135+
],
136+
137+
"DEFAULT_THROTTLE_RATES": {
138+
"anon": "20/min", # 🔒 usuarios no autenticados
139+
"user": "100/min", # 🔒 usuarios autenticados
140+
},
131141
}
132142

133143
SIMPLE_JWT = {
@@ -169,3 +179,9 @@
169179
},
170180
}
171181

182+
REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"].update({
183+
"login": "5/min", # 🔥 solo 5 intentos por minuto por IP
184+
})
185+
186+
if "pytest" in sys.argv[0]:
187+
REST_FRAMEWORK["DEFAULT_THROTTLE_CLASSES"] = []

myproject/urls.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
TokenObtainPairView,
66
TokenRefreshView,
77
)
8+
from users.views import CustomTokenObtainPairView
89

910
urlpatterns = [
1011
path('admin/', admin.site.urls),
1112
path('api/', include('users.urls')),
12-
path('api/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
13+
# path('api/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
14+
path("api/login/", CustomTokenObtainPairView.as_view(), name="token_obtain_pair"),
1315
path('api/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
1416
path('api/', include('products.urls')),
1517
]

tests/conftest.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import pytest
22
from rest_framework.test import APIClient
33
from django.contrib.auth import get_user_model
4+
from django.core.cache import cache
45
from factories import AdminFactory, StaffFactory, UserFactory
56

67
User = get_user_model()
78

9+
@pytest.fixture(autouse=True)
10+
def clear_throttle_cache():
11+
cache.clear()
812

13+
@pytest.fixture(autouse=True)
14+
def disable_throttling(settings):
15+
settings.REST_FRAMEWORK["DEFAULT_THROTTLE_CLASSES"] = []
16+
917
@pytest.fixture
1018
def api_client():
1119
return APIClient()
@@ -37,6 +45,8 @@ def _get_token(user):
3745
},
3846
format="json"
3947
)
40-
return response.data["access"]
4148

49+
assert response.status_code == 200, f"Login failed: {response.status_code} - {response.data}"
50+
51+
return response.data["access"]
4252
return _get_token

users/throttles.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from rest_framework.throttling import SimpleRateThrottle
2+
3+
4+
class LoginRateThrottle(SimpleRateThrottle):
5+
scope = "login"
6+
7+
def get_cache_key(self, request, view):
8+
# limitamos por IP
9+
ident = self.get_ident(request)
10+
return self.cache_format % {
11+
"scope": self.scope,
12+
"ident": ident
13+
}

users/views.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@
1111
LoginSerializer,
1212
ChangePasswordSerializer
1313
)
14+
from rest_framework_simplejwt.views import TokenObtainPairView
15+
from .throttles import LoginRateThrottle
16+
import sys
17+
18+
class CustomTokenObtainPairView(TokenObtainPairView):
19+
if "pytest" in sys.argv[0]:
20+
throttle_classes = []
21+
else:
22+
throttle_classes = [LoginRateThrottle]
1423

1524
class UserViewSet(viewsets.ModelViewSet):
1625
"""

0 commit comments

Comments
 (0)