models.py:
class CustomUser(AbstractUser):
username = models.CharField(max_length=80,unique=True)
email = models.EmailField(unique=True)
otp = models.IntegerField(null=True,blank=True)
activation_key = models.CharField(max_length=150,blank=True,null=True)
urls.py:
urlpatterns = [
path('signup/', signup,name = "sign_up"),
path('signup_verify/<int:otp>/', signupVerify,name = "signup_verify"),
]
使用以下命令安装 pyotp:
pip install pyotp
文档: pyotp
这里使用基于时间的 OTPs:
views.py:
from rest_framework import status
from django.contrib.auth import get_user_model
from .serializers import SignUpSerializer
from rest_framework.decorators import api_view, permission_classes
import pyotp
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from django.core.mail.message import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.conf import settings
User = get_user_model()
class generateKey:
@staticmethod
def returnValue():
secret = pyotp.random_base32()
totp = pyotp.TOTP(secret, interval=86400)
OTP = totp.now()
return {"totp":secret,"OTP":OTP}
@api_view(['POST'])
@permission_classes([AllowAny,])
def signup(request):
serializer = SignUpSerializer(data=request.data)
if serializer.is_valid():
key = generateKey.returnValue()
user = User(
username = serializer.data['username'],
email = serializer.data['email'],
otp = key['OTP'],
activation_key = key['totp'],
)
try:
validate_password(serializer.data['password'], user)
except ValidationError as e:
return Response(str(e), status=status.HTTP_400_BAD_REQUEST)
user.set_password(serializer.data['password'])
user.is_active = False
user.save()
email_template = render_to_string('signup_otp.html',{"otp":key['OTP'],"username":serializer.data['username']})
sign_up = EmailMultiAlternatives(
"Otp Verification",
"Otp Verification",
settings.EMAIL_HOST_USER,
[serializer.data['email']],
)
sign_up.attach_alternative(email_template, 'text/html')
sign_up.send()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([AllowAny,])
def signupVerify(request,otp):
try:
user = User.objects.get(otp = otp,is_active = False)
_otp = user.otp
if otp != _otp:
return Response({"Otp" : "Invalid otp"},status=status.HTTP_406_NOT_ACCEPTABLE)
else:
activation_key = user.activation_key
totp = pyotp.TOTP(activation_key, interval=86400)
verify = totp.verify(otp)
if verify:
user.is_active = True
user.save()
email_template = render_to_string('signup_otp_success.html',{"username":user.username})
sign_up = EmailMultiAlternatives(
"Account successfully activated",
"Account successfully activated",
settings.EMAIL_HOST_USER,
[user.email],
)
sign_up.attach_alternative(email_template, 'text/html')
sign_up.send()
return Response({"Varify success" : "Your account has been successfully activated!!"}, status=status.HTTP_202_ACCEPTED)
else:
return Response({"Time out" : "Given otp is expired!!"}, status=status.HTTP_408_REQUEST_TIMEOUT)
except:
return Response({"No User" : "Invalid otp OR No any inactive user found for given otp"}, status=status.HTTP_400_BAD_REQUEST)
signup_otp.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Otp Verification</title>
</head>
<body>
<h1>Otp Verification</h1>
<hr>
<small>Hello, {{username}}</small>
<p>Your Otp is <span style="font-weight: bolder; font-size: larger; background-color: rgb(230, 233, 236); padding: 4px;">{{otp}}</span></p>
<p>This otp is valid for 1 day only..</p>
<em>Thank you</em><br/>
<em>Team <b>Company name</b></em>
</body>
</html>
signup_otp_success.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Account successfully activated</title>
</head>
<body>
<h1>Welcome <strong>{{username}}</strong></h1>
<hr>
<p>Your account successfully activated.Now you can access all the feature of this site!!</p>
<h6>Have a great day {{username}}</h6>
<small>Team Company Name.</small>
</body>
</html>