i have this problem .. authenticate function in django give me none while passing username and password
here is my model
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
class myUserExtensionManager(BaseUserManager):
def create_user(self, username, email, TypeOfUser, password=None):
if not username:
return ValueError("user must have username")
if not email:
return ValueError("user must have an email address")
if not TypeOfUser:
return ValueError("user must have type novice or expert")
user = self.model(
username=username,
email=self.normalize_email(email),
TypeOfUser=TypeOfUser,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, email, password, TypeOfUser):
user = self.create_user(
username=username,
email=self.normalize_email(email),
password=password,
TypeOfUser=TypeOfUser
)
user.is_superuser = True
user.is_admin = True
user.is_staff = True
user.save(using=self._db)
return user
# Create your models here.
class UserExtensionApi(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=20, unique=True)
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
TypeOfUser = models.CharField(max_length=6)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'username' # for using for login
REQUIRED_FIELDS = ['email', 'TypeOfUser']
Manager = myUserExtensionManager()
objects = myUserExtensionManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None): # permation
return self.is_admin
def has_module_prems(self, app_label): # they permation if they admin
return True
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
and i import the obtain_auth_token from restframework django and this is the url file
from django.contrib import admin
from django.urls import path
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
path('admin/', admin.site.urls),
path('register/', Registration_view, name="register"),
path('signIn/', obtain_auth_token, name="signIn"),
]
finally i'm sending the username and password from reactjs using axios and i'm sure that the data is received in django but the result of authenticate function is always give's me None and i don't know why
Related
When I try to register a user, adapting what I learnt from Building a Custom User Model with Extended Fields youtube tutorial, I can't login afterwards despite providing the same password. However I can log in for any I created through the command line. Here is the views.py part that deal with user registration:
views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import get_user_model
from django.conf import settings
User = settings.AUTH_USER_MODEL
from django.db import IntegrityError
from django.contrib.auth import login, logout, authenticate
from .forms import TodoForm
from .models import Todo
from django.utils import timezone
from django.contrib.auth.decorators import login_required
def home(request):
return render(request, 'todo/home.html')
def signupuser(request):
if request.method == 'GET':
return render(request, 'todo/signupuser.html', {'form':UserCreationForm()})
else:
if request.POST['password1'] == request.POST['password2']:
try:
db = get_user_model()
user = db.objects.create_user(request.POST['email'], request.POST['username'],
request.POST['firstname'], request.POST['company'], request.POST['mobile_number'],
password=request.POST['password1'])
user.save()
login(request, user)
print("after login", request, user, request.POST['password1'])
return redirect('currenttodos')
def loginuser(request):
if request.method == 'GET':
return render(request, 'todo/loginuser.html', {'form':AuthenticationForm()})
else:
user = authenticate(request, username=request.POST['username'], password=request.POST['password'])
print("in login: ", request.POST['username'], request.POST['password'])
if user is None:
return render(request, 'todo/loginuser.html', {'form':AuthenticationForm(), 'error':'Username and password did not match'})
else:
login(request, user)
return redirect('currenttodos')
The user is still registered but I can't login to my website login page with the password I provided on the sign up page. Even if the user was created.
Example
I tested with: james#gmail.com and the password James.1234. It created the user:
As you can see, a password is registered.
But I was sent back to the login page, where I tried to login again but the password didn't match:
And not to currenttodos. Here are the logs:
after login <WSGIRequest: POST '/signup/'> james#gmail.com James.1234
[21/Jan/2023 20:04:16] "POST /signup/ HTTP/1.1" 302 0
[21/Jan/2023 20:04:16] "GET /current/ HTTP/1.1" 302 0
[21/Jan/2023 20:04:16] "GET /login?next=/current/ HTTP/1.1" 301 0
[21/Jan/2023 20:04:16] "GET /login/?next=/current/ HTTP/1.1" 200 3314
in login: james#gmail.com James.1234
[21/Jan/2023 20:04:41] "POST /login/?next=/current/ HTTP/1.1" 200 3468
I can't even log in for anybody but the user I created through the command line ... What could be the reason?
Here is my custom user model:
models.py:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
class CustomAccountManager(BaseUserManager):
def create_superuser(self, email, user_name, first_name, 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.')
return self.create_user(email, user_name, first_name, password, **other_fields)
def create_user(self, email, user_name, first_name, company, mobile_number, password, **other_fields):
if not email:
raise ValueError(('You must provide an email address'))
email = self.normalize_email(email)
user = self.model(email=email, user_name=user_name, first_name=first_name,
company=company, mobile_number=mobile_number, password=password, **other_fields)
user.set_password(password)
user.save()
return user
class Newuser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(('email address'), unique=True)
user_name = models.CharField(max_length=150, unique=True)
first_name = models.CharField(max_length=150, blank=True)
mobile_number = models.CharField(max_length=10)
company = models.CharField(max_length=5)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
objects = CustomAccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['user_name', 'first_name', 'mobile_number']
def __str__(self):
return self.user_name
settings.py
AUTH_USER_MODEL = 'todo.NewUser'
I am unable to authenticate custom user in django==3.1.3
Here is Custom User Manager:
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _
class CustomUserManager(BaseUserManager):
def create_user(self, username, email, password=None):
if username is None:
raise TypeError(_('Users should have a username.'))
if email is None:
raise TypeError(_('Users should have a Email.'))
user = self.model(username=username, email=self.normalize_email(email))
user.set_password(password)
user.save()
return user
def create_superuser(self, username, email, password=None):
if password is None:
raise TypeError(_('Password should not be empty.'))
user = self.create_user(username, email, password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
Here's the CustomUser model:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from .managers import CustomUserManager
class CustomUser(AbstractBaseUser):
username = models.CharField(max_length=255, unique=True, db_index=True)
email = models.EmailField(max_length=255, unique=True, db_index=True)
is_verified = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = CustomUserManager()
def __str__(self):
return self.email
I have added AUTH_USER_MODEL = 'authentication.CustomUser' in settings.py
(authentication is the app name)
In the shell, if I run these, I get authenticated_user as None:
user = CustomUser.objects.create(email='tejas#gmail.com', username='tejas12', password='tejas12')
authenticated_user = authenticate(email='tejas#gmail.com', username='tejas12', password='tejas12')
However, the User gets created successfully with given details.
Also, check_password returns False:
from django.contrib.auth.hashers import check_password
user.check_password('tejas12') # returns False
On creating a user using python manage.py createsuperuser,
authenticate returns the required user, and
check_password returns True
How should I authenticate the custom users?
In your example, you create the user as a regular Django model which doesn't hash password properly
user = CustomUser.objects.create(email='tejas#gmail.com', username='tejas12', password='tejas12')
create_user method should be used instead
>>> second_user = CustomUser.objects.create_user(email='test#example.com', username='test', password='test_passwd')
>>> second_user.check_password('test_passwd')
True
Authentication uses default backend unless you specify your own and will rely on the USERNAME_FIELD and password
>>> from django.contrib.auth import authenticate
>>> authenticate(email='test#example.com', username='test', password='test_passwd')
>>> authenticate(email='test#example.com', password='test_passwd')
<CustomUser: test#example.com>
I followed a tutorial on how to allow Django authentication by using email instead of the normal username, however, they didn't mention how to register the new custom user model with the admin page! I am a real beginner to Django so I would appreciate as much detail as possible! Here is my code so far:
managers.py
from django.contrib.auth.models import BaseUserManager
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **kwargs):
if not email:
raise ValueError('Email field is required')
email = self.normalize_email(email)
user = self.model(email=email, **kwargs)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
return self.create_user(email, password, **extra_fields)
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.utils.translation import gettext_lazy as _
from .managers import CustomUserManager
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, null=True)
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this admin site.'),
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. ''Unselect this instead of deleting accounts.'
),
)
USERNAME_FIELD = 'email'
objects = CustomUserManager()
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
return self.email
def get_short_name(self):
return self.get_full_name()
def __str__(self):
return self.email
admin.py
from django.contrib import admin
# Register your models here.
try this code in your admin.py
We can register our models with register decorator.
from django.contrib import admin
from .models import CustomUser
#admin.register(CustomUser)
class CustomUserAdmin(admin.ModelAdmin):
pass
from .models import CustomUser
class CustomUserAdmin(admin.ModelAdmin):
list_display = ('email',...) # add fields as you want
admin.site.register(CustomUser, CustomUserAdmin)
I wanted to customize Django's builtin authentication system to replace username with email (i.e. use an email/password combination instead of a username/password combination for login), so I made a custom User model by subclassing AbstractBaseUser and PermissionsMixin and a custom UserManager, then set settings.AUTH_USER_MODEL = 'myapp.User' to enable it.
Everything works fine, but the problem is, the login form as generated by django.contrib.auth.views.LoginView uses name="username" type="text" and label id id_username for the email input field (in spite of using the correct label string "Email address"). The login form works regardless, but it's wrong semantically and the HTML5 client-side validation doesn't work this way. Note that this isn't a problem in the registration form; it names the email field as email rather than username, as expected.
Here's the code:
models.py:
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.db import models
from django.utils.translation import ugettext_lazy as _
from .managers import UserManager
class User(AbstractBaseUser, PermissionsMixin):
first_name = models.CharField(_('first name'), max_length=30)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(_('email address'), unique=True)
date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
is_active = models.BooleanField(_('active'), default=False)
verification_code = models.CharField(_('verification code'), max_length=32,
blank=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name']
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def __str__(self):
return self.email
def get_full_name(self):
'''
Return first_name plus the last name, with a space in between.
'''
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
'''
Return short name (first name) for the user.
'''
return self.first_name
managers.py
from django.contrib.auth.base_user import BaseUserManager
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
'''
Create and save a User with the given email and password.
'''
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True')
return self._create_user(email, password, **extra_fields)
settings.py
...
# Redirect to my URL after login
LOGIN_REDIRECT_URL = '/'
# Custom login backend (using email instead of username)
AUTH_USER_MODEL = 'myapp.User'
...
urls.py
from django.conf.urls import url
from django.contrib.auth import views as auth_views
from . import views
urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^accounts/register/$', views.register, name='register'),
url(r'^accounts/login/$', views.login, name='login'),
url(r'^accounts/logout/$', auth_views.LogoutView.as_view(),
{'next_page': '/'}, name='logout'),
url(r'^accounts/verify/(?P<code>[a-zA-Z0-9]{32})$', views.verify,
name='verify'),
]
views.py
...
from django.contrib.auth.views import LoginView
from django.http import HttpResponseRedirect
from django.urls import reverse
from . import util
from .forms import RegistrationForm
...
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.verification_code = get_random_string(length=32)
user.save()
res = util.send_verification_email(request, user)
if not res.ok:
logging.error(res.text)
return HttpResponse(status=500)
return render(request, 'registration/registration_complete.html')
else:
form = RegistrationForm()
token = {}
token.update(csrf(request))
token['form'] = form
return render(request, 'registration/register.html', token)
def login(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('home'))
else:
return LoginView.as_view()(request)
...
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import User
class RegistrationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = ('first_name', 'last_name', 'email')
widgets = {
'first_name': forms.TextInput(attrs={'placeholder': 'John',
'autofocus': 'true'}),
'last_name': forms.TextInput(attrs={'placeholder': 'Doe'}),
'email': forms.TextInput(attrs={'placeholder':
'johndoe#example.com'}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['email'].widget.attrs.pop('autofocus')
Templates generate the form using a for-loop on {{ form }}.
I realize that I'm using a custom registration form as defined in forms.py, but I have no idea how to do the same with the login form and I couldn't find anything online or in the docs.
What am I missing?
I don't understand why you're using LoginView at all. Logging a user in is just a few lines of code and is perfectly easy to do in your own view.
Additionally, it's really not good practice to call a view directly from another view.
But if you really want to use the LoginView, you need to subclass AuthenticationForm and then pass that form class into the LoginView call:
return LoginView.as_view(authentication_form=MyAuthFormClass)(request)
I have a custom user model and a user manager defined as follows:
/accounts/models.py
from django.contrib.auth.models import (
AbstractBaseUser,
BaseUserManager,
PermissionsMixin
)
from django.db import models
from django.utils import timezone
class UserManager(BaseUserManager):
def create_user(self, email, first_name, last_name, username=None, password=None):
if not email:
raise ValueError("Users must have a valid email address")
if not first_name and last_name:
raise ValueError("Users must have a first and last name")
created_username = ''.join([first_name.lower(), last_name[:1].lower()])
i=2
while User.objects.filter(username=created_username).exists():
created_username = ''.join([first_name.lower(), last_name[:i].lower()])
i+=1
user = self.model(
email=self.normalize_email(email),
first_name=first_name,
last_name=last_name,
username=created_username
)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name,
last_name,
password
)
user.is_staff = True
user.is_admin = True
user.is_superuser = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=40, blank=True)
last_name = models.CharField(max_length=40, blank=True)
username = models.CharField(max_length=40, unique=True, blank=True, editable=False)
# display_name = models.CharField(max_length=150)
bio = models.TextField(blank=True, null=True)
avatar = models.ImageField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name','last_name']
def __str__(self):
return "{} #{}".format(self.email, self.username)
def get_short_name(self):
return self.first_name
def get_full_name(self):
return ' '.join([self.first_name, self.last_name])
This seems to work perfectly when registering a superuser from the shell. I have a form and a view set up to register regular users on my site as follows:
/accounts/forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
auth_code = 'hamburger'
def validate_authorization(value):
if value != auth_code:
raise ValidationError(
_('Must have valid authorization code in order to register.')
)
class UserCreateForm(UserCreationForm):
authorization_code = forms.CharField(max_length=10, required=True, validators=[validate_authorization])
class Meta:
model = get_user_model()
fields = ("email", "first_name", "last_name", "password1", "password2", "authorization_code")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["email"].label = "Email Address"
self.fields["first_name"].label = "First Name"
self.fields["last_name"].label = "Last Name"
self.fields["password1"].label = "Password"
self.fields["password2"].label = "Password Confirmation"
self.fields["authorization_code"].label = "Authorization Code"
/accounts/views.py
from django.shortcuts import render
from django.template import RequestContext
from django.contrib.auth import login, logout
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.core.urlresolvers import reverse_lazy
from django.views import generic
from django.http import HttpResponseRedirect
from django.contrib.auth import get_user_model
from . import forms
class SigninView(generic.FormView):
form_class = AuthenticationForm
success_url = '/dashboard/' #reverse_lazy('index')
template_name = 'accounts/signin.html'
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
return form_class(self.request, **self.get_form_kwargs())
def form_valid(self, form):
login(self.request, form.get_user())
return super().form_valid(form)
class SignoutView(generic.RedirectView):
url = '/' #reverse_lazy("home")
def get(self, request, *args, **kwargs):
logout(request)
return super().get(request, *args, **kwargs)
class RegisterView(generic.CreateView):
form_class = forms.UserCreateForm
success_url = '/'
template_name = 'accounts/register.html'
def form_valid(self, form):
self.object = form.save(commit=False)
form.instance.username = ''.join([form.instance.first_name.lower(), form.instance.last_name[:1].lower()])
i=2
while get_user_model().objects.filter(username=form.instance.username).exists():
form.instance.username = ''.join([form.instance.first_name.lower(), form.instance.last_name[:i].lower()])
i+=1
form.save()
return HttpResponseRedirect(self.get_success_url())
# return super(RegisterView, self).form_valid(form)
I am at a loss as to why my superuser cannot log into the website but my regular users can. Also you will notice I have a while statement that auto generates a username based on the entered first and last name. Initially I had this only in the UserManager however, the form was bypassing the user manager and so I had to add the same block of code to my view. So there seems to be a disconnect between users created from the form versus users created from the shell (UserManager).
The authorization_code is in place because I don't want just anybody to be able to register on my site and I didn't know a better way. I am open to better suggestions.
Additional information that may be helpful
settings.py
# Set user authentication model
AUTH_USER_MODEL = 'accounts.User'
Python 3.5, Django 1.10
Thank you in advance for any advice or insight.
Problem solved.
In
def create_superuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name,
last_name,
password
)
I was forgetting to set password=password,. From looking at the password field in the database, it seems this was also resulting in (as close as I can tell) bypassing <algorithm>$<iterations>$<salt> (per the Django docs https://docs.djangoproject.com/en/1.10/topics/auth/passwords/) though the password was still being hashed in some way (not being stored in plain text) the password field for superusers was considerably shorter than the password field for normal users. Whatever it was doing, it was not storing the actual password and was giving me an invalid username/password when attempting to log in with a superuser account.
So the proper way is
def create_superuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name,
last_name,
password=password,
)
I still don't understand why created_username is being bypassed in the UserManager when saving a user from the AuthenticationForm but I found a workaround by adding the same while statement to the view. At least all is functional now. I'm still interested to learn if anybody has further insight into this matter.