Reputation: 61
I'm trying to code the login/register system on Django, but I'm getting errors. So my main task is to make a custom auth system that the user can easily login/logout/register. I don't want to use the in-built User model, I want to use my main from flask. So the thing is that I'm trying to move from flask to Django and set-up the models and stuff. So I have this models.py file which concludes:
import datetime
import uuid
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.db import models
from werkzeug.security import generate_password_hash, check_password_hash
class UserManager(BaseUserManager):
def create_user(self, username, password, primary_telephone_number, secondary_telephone_number, primary_email_address, first_name, last_name, registration_ip):
if not username or not password or not primary_telephone_number or not secondary_telephone_number or not primary_email_address or not first_name or not last_name or not registration_ip:
raise ValueError('Not enough values')
user_obj = self.model(username=username,
password=generate_password_hash(password),
primary_telephone_number=primary_telephone_number,
secondary_telephone_number=secondary_telephone_number,
primary_email_address=primary_email_address,
first_name=first_name,
last_name=last_name,
registration_ip=last_name)
user_obj.save(using=self._db)
return user_obj
class Users(AbstractBaseUser):
"""Model for Winteka.IOT Users."""
public_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, blank=False, null=False, max_length=36)
username = models.CharField(max_length=50, unique=True, blank=False, null=False)
password = models.CharField(max_length=80, blank=False, null=False)
# Third-party social (Emails, Phone numbers, Verifications)
primary_telephone_number = models.CharField(max_length=15, unique=False, null=True, blank=False)
secondary_telephone_number = models.CharField(max_length=15, unique=False, null=True, blank=True)
primary_telephone_number_verified = models.BooleanField(default=False, null=False, blank=False) #Default
secondary_telephone_number_verified = models.BooleanField(default=False, null=False, blank=False) #Default
primary_email_address = models.EmailField(max_length=320, unique=True, blank=False, null=True)
recovery_email_address = models.EmailField(max_length=320, null=True, blank=True, unique=True, default=None) #Default
primary_email_address_verified = models.BooleanField(null=False, blank=False, default=False) #Default
recovery_email_address_verified = models.BooleanField(null=False, blank=False, default=False) #Default
# User Profile Stuff...
first_name = models.CharField(max_length=26, null=True, blank=True)
last_name = models.CharField(max_length=35, null=True, blank=True)
profile_bio = models.CharField(max_length=200, default="This user wants to keep a secret about himself.",
null=False, blank=False) #Default
profile_picture = models.CharField(max_length=20, default="profile_picture", null=False, blank=False) #Default
profile_cover_picture = models.CharField(max_length=20, default="profile_cover_picture", null=True, blank=False) #Default
profile_qr_code = models.CharField(max_length=20, default="qr_code", null=False, blank=False) #Default
# Account administration
role = models.CharField(max_length=20, blank=False, null=False, default='user') #Default
reports = models.IntegerField(blank=False, null=False, default=0) #Default
warnings = models.IntegerField(blank=False, null=False, default=0) #Default
frozen = models.BooleanField(blank=False, null=False, default=False) #Default
suspended = models.BooleanField(blank=False, null=False, default=False) #Default
# Purchases * Balance Tracking
balance = models.DecimalField(max_digits=11, decimal_places=2, blank=False, null=False, default=0.00) #Default
subscriptions_bought = models.IntegerField(null=False, blank=False, default=0) #Default
total_purchases = models.IntegerField(blank=False, null=False, default=0) #Default
total_deposit = models.DecimalField(max_digits=11, decimal_places=2, blank=False, null=False, default=0.00) #Default
total_withdraw = models.DecimalField(max_digits=11, decimal_places=2, blank=False, null=False, default=0.00) #Default
lastAccessedTime = models.CharField(max_length=36, blank=False, null=False,
default=datetime.datetime.now().strftime('%Y-%m-%d %H:%M.%S')) #Default
# First Registration.
first_login = models.CharField(max_length=36, null=False, blank=False,
default=datetime.datetime.now().strftime('%Y-%m-%d %H:%M.%S')) #Default
default_language = models.CharField(max_length=3, null=False, blank=False, default="EN") #Default
registration_ip = models.CharField(max_length=32, blank=False, null=False)
# Subscriptions & Purchases
devices = models.IntegerField(blank=False, null=False, default=0) #Default
# Third-Party Login System (Unfinished)
google_authorized = models.BooleanField(blank=False, null=False, default=False) #Default
google_client_id = models.CharField(max_length=36, blank=True, null=True, default=None) #Default
facebook_authorized = models.BooleanField(blank=False, null=False, default=False) #Default
facebook_client_id = models.CharField(max_length=36, blank=True, null=True, default=None) #Default
# Location services. Street address & more.
primary_street_address = models.CharField(max_length=95, blank=True, null=True, default=None) #Default
secondary_street_address = models.CharField(max_length=95, blank=True, null=True, default=None) #Default
zip_code = models.CharField(max_length=6, blank=True, null=True, default=None) #Default
region = models.CharField(max_length=6, blank=True, null=True, default=None) #Default
country = models.CharField(max_length=63, blank=True, null=True, default=None) #Default
city = models.CharField(max_length=28, blank=True, null=True, default=None) #Default
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['password', 'primary_telephone_number', 'secondary_telephone_number', 'primary_email_address', 'first_name', 'last_name', 'registration_ip']
objects = UserManager()
def create_password(self, password):
"""Create hashed password."""
return generate_password_hash(self.password, method="sha256")
def check_password(self, password):
"""Check hashed password."""
return check_password_hash(self.password, password)
def __str__(self):
return "User {}".format(self.id)
class Meta:
verbose_name_plural = "Users"
My register logic is this:
def register(request):
if request.user.is_authenticated:
return HttpResponseRedirect(settings.MAIN_REDIRECT_URL)
if request.method == 'GET':
if request.user.is_authenticated:
return HttpResponseRedirect(settings.MAIN_REDIRECT_URL)
return render(request, 'authn/register.html')
elif request.method == 'POST':
if request.user.is_authenticated:
return HttpResponseRedirect(settings.MAIN_REDIRECT_URL)
email_address = request.POST.get('acc_primary_email_address', None)
password = request.POST.get('acc_password', None)
username = request.POST.get('acc_username', None)
primary_phone_number = request.POST.get('acc_primary_phone_number', None)
print(email_address, password, username, primary_phone_number)
_ip_address_ = get_client_ip(request)
if _ip_address_ in settings.ADMINISTRATOR_IPS:
# TODO Create log system and log when administrator or mod appears online.
pass
if _ip_address_ is None:
messages.success(request, f'Our systems have temporarily blocked traffic from this IP Address.')
return render(request, 'authn/register.html')
# Check for user...
existing_user = Users.objects.filter(primary_email_address=email_address).first()
if existing_user:
messages.error(request, 'User with this email address exists!')
return render(request, 'authn/login.html')
user = Users.objects.create_user(
username=username,
password=password,
primary_telephone_number='4124124151255',
secondary_telephone_number='41244124',
primary_email_address=email_address,
first_name='fname',
last_name='lname',
registration_ip='5.20.236.256'
)
user.save()
messages.success(request, 'new_acc test')
return render(request, 'authn/login.html')
And I would like to ask is this is a good structure of everything? Because as I saw some tutorials that people are using some in-built functions as user.set_password()
, do I need this? I have my own sha256 hash, but I still don't understand the functioning principle of Django auth. So as I made this module and tried to launch it, I had many errors, but now I'm stuck on this one. I have my registration_ip
max char length set to 32, but the error says that It's set to 80. So the main question is if I'm doing everything as I should?
Also, I have my templates and static files, so I just use render
function to return a template, so I don't need to use the views
or as_view
functions from Django, or Should I?
Upvotes: 1
Views: 201
Reputation:
The built-in things in Django, especially authentication are tried and tested and follow industry standards (for example, Django's default hasher changes its number of iterations every few releases). The difficulty is knowing when to deviate and to choose the right path to do so.
I think you're on the wrong path here and the Django documentation on authentication and custom users is actually an excellent resource on how to customize it. I would highly suggest to take small detour, create a test project and follow the guide. Pay attention to:
UserManager._create_user()
in the final step or I use a long living active library like Django allauth, so I can benefit from any fixes or improvements that Django puts in.To stress the last point: millions of users are using the Django authentication (without knowing it) and while authentication is not hard to do, it also not hard do it wrong and it's better to trust the protocol that many others in the industry keep a close eye on.
Upvotes: 1
Reputation: 61
The main reason was that I was basically using the wrong max_length
value, I didn't saw that I have some fields that were had max_length=20
, but they contain more than 20 char.
This value had wrong settings.
profile_cover_picture = models.CharField(max_length=20, default="profile_cover_picture", null=True, blank=False) #Default
Change to this:
profile_cover_picture = models.CharField(max_length=30, default="profile_cover_picture", null=True, blank=False) #Default
Upvotes: 0