پیاده سازی گوگل 2FA در جنگو

روش Google Authenticator یک احراز هویت مبتنی بر نرم‌افزار توسط Google عه که خدمات تأیید دو مرحله‌ای را با استفاده از الگوریتم گذرواژه یکبار مصرف مبتنی بر زمان و الگوریتم رمز عبور یک‌بار مبتنی بر HMAC برای احراز هویت کاربران برنامه‌های نرم‌افزاری پیاده‌سازی می‌کنه.برای پیاده سازی این روش تو جنگو اول یه مدل به این شکل میسازیمclass AuthInformation(models.Model): secret_key = models.CharField(max_length=512 , unique=True) user = models.OneToOneField('account.User' , on_delete=models.CASCADE)من از کتابخونه pyotp استفاده کردم که با این دستور نصب میشه:pip install pyotp داکیومنت این کتابخونه رو هم میتونید از اینجا بخونید.https://pyotp.readthedocs.io/en/stable/معمولا تو سایت ها دیدیم که این روش برای اهراز هویت رو خوده کاربر فعالش میکنه پس نیازه یه فیلد بولین به مدل یوزر اضافه کنیم.من فیلد is_2FA_activate رو تو کلاس یوزر به این شکل اضافش کردم:class User(AbstractUser): is_2FA_active = models.BooleanField(default=False) یه api هم نیازه که کاربر اونو کال کنه و این فیلد رو ترو کنه. وقتی کاربر این فیلد رو کال میکنه از مدل AuthInformation که ساخته بودیم برا این یوزر هم بسازیم.@decorators.api_view(['GET', ]) @decorators.permission_classes([perms.IsAuthenticated, ]) def active_2FA(request): import pyotp from authentication.models import AuthInformation user = request.user user.is_2FA_active = True user.save() while True: auth, crt = AuthInformation.objects.get_or_create( user=user, ) if crt: try: secret_key = pyotp.random_base32() auth.secret_key = secret_key auth.save() break except: pass else: break return response.Response({'result' :&quotبا موفقیت فعال شد.&quot , &quotsecret_key&quot : auth.secret_key})سکرت کی مورد نیاز برای کاربر توسط تابع: pyotp.random_base32()ساخته میشه.حالا باید سکرت کیی که توسط برنامه ساخته شده رو به یه نرم افزار تولید این کد بدیم تا اون رو استفاده کنیم.(این روش جزو Time-based OTP ها هستش و ما از توابع Time-Based های کتابخونه pyotp استفاده میکنیم.)من از اکستنشن Authenticator برای این کار استفاده کردم.حالا کد وریفای رو در ادامه داریم:username = request.data.get('username') password = request.data.get('password') user = authenticate(username=username, password=password) if not user: return response.Response({'detail': &quotنام کاربری یا رمز عبور اشتباه است&quot}, status=status.HTTP_400_BAD_REQUEST) if user.is_2FA_active: from authentication.models import AuthInformation import pyotp auth_info_detail = AuthInformation.objects.get(user_id = user.id) secret_key = auth_info_detail.secret_key pin = request.data.get('pin') if pin is None: return response.Response({&quotdetail&quot: &quotکد وارد نشده است.&quot}, status=status.HTTP_400_BAD_REQUEST) totp = pyotp.TOTP(secret_key) verification_status = totp.verify(pin) if verification_status: pass else: return response.Response({&quotdetail&quot : &quotکد وارد شده اشتباه است.&quot}, status = status.HTTP_400_BAD_REQUEST) data = serializers.UserSerializers(user).data token = get_tokens_for_user(user) data['access'] = token['access'] data['refresh'] = token['refresh'] return response.Response(data, status=status.HTTP_200_OK)من این تابع رو به صورت POST نوشتم که باید نام کاربری ، رمز عبور و کد جنربت شده رو(درصورت فعال بودن این روش برای کاربر) ارسال کنید که اگه درست بود توکن کاربر بهش برگردونده بشه.امیدوارم مفید باشه براتون.