Django auth with otp and phone number without password
I want user login without password, just by sending an SMS to the user's phone number and entering the code. I used sessions to transfer user inputs and I just don't know if this is correct or if there is a better way for this? Is my model implementaion is correct ? This is my code:
# models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
class MyAccountManager(BaseUserManager):
def create_superuser(self,username, email, phone_number,password, **other_fields):
other_fields.setdefault('is_staff', True)
other_fields.setdefault('is_superuser', True)
other_fields.setdefault('is_active', True)
if other_fields.get('is_staff') is not True:
raise ValueError('Superuser must be assigned to is_staff=True')
if other_fields.get('is_superuser') is not True:
raise ValueError('Superuser must be assigned to is_superuser=True')
user = self.create_user(username,email, phone_number, password, **other_fields)
user.set_password(password)
user.save()
return user
def create_user(self, username, email, phone_number,password,**other_fields):
if not email:
raise ValueError('')
email = self.normalize_email(email)
if password is not None:
user = self.model(username=username,email=email, phone_number=phone_number,password=password, **other_fields)
user.save()
else:
user = self.model(username=username,email=email, phone_number=phone_number, password=password,**other_fields)
user.set_unusable_password()
user.save()
return user
class Account(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=150,unique=True)
phone_number = models.CharField(max_length=17, unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
objects = MyAccountManager()
USERNAME_FIELD = 'phone_number'
REQUIRED_FIELDS = ['email', 'username']
# views.py
from django.shortcuts import render, redirect, HttpResponse
from django.contrib.auth import authenticate, login, get_user_model
from .forms import RegisterForm, LoginForm, OtpConfirmForm
from django.contrib.auth.backends import ModelBackend
User = get_user_model()
class PasswordlessAuthBackend(ModelBackend):
# Log in to Django without providing a password.
def authenticate(self, request, phone_number):
User = get_user_model()
try:
user = User.objects.get(phone_number=phone_number)
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
User = get_user_model()
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
def login_view(request):
form = LoginForm(request.POST or None)
context = {'form': form}
if form.is_valid():
request.session['phone_number'] = form.cleaned_data.get('phone_number')
request.session['otp'] = 12345
# sendin otp functionality
return redirect('login-confirm')
return render(request, 'login.html', context)
def login_confirm_view(request):
form = OtpConfirmForm(request.POST or None)
context = {'form': form}
if form.is_valid():
phone_number = request.session['phone_number']
form_otp = form.cleaned_data.get('otp')
session_otp = request.session['otp']
if form_otp == session_otp:
user = authenticate(request, phone_number=phone_number)
if user is not None:
login(request, user, backend='account.views.PasswordlessAuthBackend')
return redirect('home')
else: return HttpResponse('invalid login')
return render(request, 'login-confirm.html', context)
Thank you for helping me.