From e9c68381715cc5080913ef1aa8d6b22549044326 Mon Sep 17 00:00:00 2001 From: Akira Date: Sun, 31 Aug 2025 12:08:36 +0900 Subject: [PATCH] Fix duplicate user registration error --- rog/urls.py | 1 + rog/views.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/rog/urls.py b/rog/urls.py index d44ca45..c114be8 100755 --- a/rog/urls.py +++ b/rog/urls.py @@ -247,6 +247,7 @@ urlpatterns += [ # App Version Management path('app/version-check/', app_version_check, name='app_version_check'), + path('api/app/version-check/', app_version_check, name='app_version_check_duplicate'), # クライアントの誤ったURL対応 path('app/version-management/', AppVersionManagementView.as_view(), name='app_version_management'), # Multi-Image Upload API diff --git a/rog/views.py b/rog/views.py index 679a631..7acda7f 100755 --- a/rog/views.py +++ b/rog/views.py @@ -74,6 +74,8 @@ from django.utils.encoding import force_str import logging from datetime import datetime,timedelta +from django.core.cache import cache +import time from django.contrib.gis.measure import D from django.contrib.gis.geos import Point @@ -2276,6 +2278,28 @@ class ResendInvitationEmailView(APIView): class TempUserRegistrationView(APIView): def post(self, request): email = request.data.get('email') + + # レート制限: 同じIPアドレスからの重複リクエストを防ぐ + client_ip = self.get_client_ip(request) + cache_key_ip = f"register_rate_limit:{client_ip}" + cache_key_email = f"register_email_limit:{email}" + + # 同じIPからの連続リクエストを制限(1分間に最大3回) + ip_requests = cache.get(cache_key_ip, 0) + if ip_requests >= 3: + logger.warning(f"レート制限: IP {client_ip} からの過剰なリクエスト") + return Response({ + "error": "リクエストが多すぎます。1分後に再試行してください。" + }, status=status.HTTP_429_TOO_MANY_REQUESTS) + + # 同じメールアドレスへの連続リクエストを制限(30秒間に1回) + email_request_time = cache.get(cache_key_email) + current_time = time.time() + if email_request_time and (current_time - email_request_time) < 30: + logger.warning(f"メール送信制限: {email} への重複リクエスト") + return Response({ + "error": "同じメールアドレスへの再送信は30秒後に可能です。" + }, status=status.HTTP_429_TOO_MANY_REQUESTS) # 本登録済みのユーザーチェック if CustomUser.objects.filter(email=email).exists(): @@ -2289,6 +2313,11 @@ class TempUserRegistrationView(APIView): reverse('rog:verify-email', kwargs={'verification_code': temp_user.verification_code}) ) send_verification_email(temp_user, verification_url) + + # キャッシュを更新 + cache.set(cache_key_ip, ip_requests + 1, 60) # 1分間 + cache.set(cache_key_email, current_time, 30) # 30秒間 + logger.info(f"既に仮登録されているユーザーに招待メールを再送信しました。Email: {email}") return Response({"message": "既に仮登録は行われていますが、招待メールを再送信しました。"}, status=status.HTTP_200_OK) except TempUser.DoesNotExist: @@ -2310,10 +2339,24 @@ class TempUserRegistrationView(APIView): reverse('rog:verify-email', kwargs={'verification_code': verification_code}) ) send_verification_email(temp_user, verification_url) + + # キャッシュを更新 + cache.set(cache_key_ip, ip_requests + 1, 60) # 1分間 + cache.set(cache_key_email, current_time, 30) # 30秒間 + logger.info(f"新規ユーザーを仮登録し、招待メールを送信しました。Email: {email}") return Response({"message": "仮登録が完了しました。招待メールを送信しました。"}, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + def get_client_ip(self, request): + """クライアントIPアドレスを取得""" + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + if x_forwarded_for: + ip = x_forwarded_for.split(',')[0] + else: + ip = request.META.get('REMOTE_ADDR') + return ip + #serializer = TempUserRegistrationSerializer(data=request.data)