5
votes

Hello all you helpful people out there (and goodbye none-helpful people :D ). I'm trying to create a user in django (1.2.4) and then log them in after saving them. My problem is I'm getting NotImplementedError and looking at the traceback it's being raised by django.contrib.auth.models.AnonymousUser . Here is part of my view code:

def signup(request):
    if request.method == 'POST': # If the form has been submitted...
        p = request.POST
        if not request.user.is_authenticated():
            form = UserForm(request.POST) # A form bound to the POST data
            if form.is_valid(): # All validation rules pass
                # Process the data in form.cleaned_data
                # ...
                form.save()
                user=authenticate(username=p['username'],password=p['password'])
                login(request,user)
                return HttpResponseRedirect('/') # Redirect after POST

So it looks to me that It's trying to log in an anymouse user instead of the one I'm authenticating, how can I overcome this?

Thanks P.S. The users are being created in the database, it just won't log them in using this code.

Traceback:

Environment:
Request Method: POST
Request URL: http://localhost:8000/signup/
Django Version: 1.2.4
Python Version: 2.6.1
Installed Applications:
['django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.admin',
'django.contrib.admindocs',
'django_extensions',
'REDACTED_APPs', Installed Middleware: ('django.middleware.common.CommonMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware')

 Traceback:    
 File "/Library/Python/2.6/site-packages/django/core/handlers/base.py" in get_response    
   100.                     response = callback(request, *callback_args, **callback_kwargs)    
 File "REDACTED/views.py" in signup    
   19.                 login(request,user)    
 File "/Library/Python/2.6/site-packages/django/contrib/auth/__init__.py" in login    
   71.     user.save()    
 File "/Library/Python/2.6/site-packages/django/contrib/auth/models.py" in save    
   430.         raise NotImplementedError    

 Exception Type: NotImplementedError at /signup/    
 Exception Value:
4

4 Answers

6
votes

What I think is happening here is authenticate is returning None, therefore login is using request.user (an AnonymousUser).

It looks like the information used to create the user is different to what you are passing to authenticate. I would double check that the user is being saved correctly (especially the password).

Edit: From other answers I see you are using a custom user form. You should use django.contrib.auth.forms.UserCreationForm, it's save() method will set the password correctly.

The below doesn't work without manually setting the backend attribute, more trouble than it's worth, left for posterity

The easy out is to skip the authenticate step here (it doesn't add anything important)

user = UserForm.save()
login(request, user)
4
votes

Creating a user with form.save() is not a good way... Because, since passwords are saved in a hashed format, pasword set by using

user.passord = password

simply writes unhashed data to the database and django auth can not check it correctly... What you need is:

username = form.cleaned_data['username']
password = form.cleaned_data['password']

user = User.objects.create(username=username)
if password:
    user.set_password(password)
else:
    user.set_unusable_password()
user.save()
3
votes

Not sure if it will help but it's best to extract form fields like the following:

username = form.cleaned_data['username']
password = form.cleaned_data['password']
hashed_password = hashlib.md5(password).hexdigest()

user = authenticate(username=username, password=hashed_password)
if user:
    login(request, user)
    return HttpResponseRedirect('/')

From the users that have been created with your current code, can you authenticate them into the system?

Here's an alternate way to create and login using a login form and creating the user manually:

# forms.py
from django import forms


class LoginForm(forms.Form):
    username = forms.CharField(max_length=20)
    password = forms.CharField(widget=forms.PasswordInput)


# views.py
import hashlib

username = form.cleaned_data['username']
password = form.cleaned_data['password']
hashed_password = hashlib.md5(password).hexdigest()

# assuming username is unique
User.objects.get_or_create(username=username, defaults={'password': hashed_password, 'is_active': True})

# If password doesn't work, try hashed_password next
user = authenticate(username=username, password=password)
if user:
    login(request, user)
    return HttpResponseRedirect('/')
0
votes

In Django 2.2 I've used the following code for signup

def signup(request):
    if request.method == 'POST':
        user_form = UserRegistrationForm(request.POST)
        if user_form.is_valid():
            # Create a new user object but avoid saving it yet
            new_user = user_form.save(commit=False)
            # Set the chosen password
            new_user.set_password(
            user_form.cleaned_data['password'])
            # Save the User object
            new_user.save()
            # Create the user profile
            Profile.objects.create(user=new_user)
            return render(request,
                          'account/register_done.html',
                          {'new_user': new_user})
    else:
        user_form = UserRegistrationForm()
    return render(request,
                  'account/register.html',
                  {'user_form': user_form})

Here we can further enhance it by calling Django hashing methods

Following are the django hashing methods:

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.Argon2PasswordHasher',
]

We can call the above hashers as follows:

from django.contrib.auth.hashers import PBKDF2PasswordHasher

class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher):
    """
    A subclass of PBKDF2PasswordHasher that uses 100 times more iterations.
    """
    iterations = PBKDF2PasswordHasher.iterations * 100

For further hashing new methods like argon2/bcrypt, we need to install argon2.

Please refer : https://docs.djangoproject.com/en/3.1/topics/auth/passwords/