user1120144
user1120144

Reputation:

AuthenticationForm not working

I'm experimenting with Django and I tried to create a login/register application. Here's where I've stuck - I'm able to register users, but then I can't login with them. Here's the code I think is relevant:

views.py

def login(request, template='accounts/sign_in.html'):
    if request.user.is_authenticated():
        return redirect(reverse('games'))
    if request.method == 'POST':
        post = request.POST.copy()
        if 'password' in post:
            post['password'] = make_password(post['password'])
        form = AuthenticationForm(data=post)

        if form.is_valid():
            login(request, form.get_user())
            messages.success(
                request, "Successfully logged in.", extra_tags='success')
            return redirect(reverse('games'))
        else:
            messages.warning(
                request, "Wrong username or password." + request.POST['username'] + " " + request.POST['password'], extra_tags='error')
            return redirect(reverse('login'))
    return views.login(request, template)

def register(request, template='accounts/sign_up.html'):
    if request.user.is_authenticated():
        return redirect(reverse('home'))
    if request.method == 'POST':
        form = RegisterForm(request.POST)
        if form.is_valid():
            new_user = User(
                username=form.cleaned_data['username'],
                password=make_password(form.cleaned_data['password1']),
                is_active=True,
            )
            new_user.save()

            messages.success(request, "Your account was successfully created.")
            return redirect(reverse('games'))
    else:
        form = RegisterForm()

    return render(request, template, {'register_form': form})

When I try to log in with a user I've created (username: qwe, password: qweqweqwe), I get redjrected to login again, but the exact same username and password are printed in the message:

Wrong username or password.qwe qweqweqwe

However, when I try the interactive shell, here's what I get:

>>> User.objects.all()
[<User: admin>, <User: asd>, <User: qwe>]
>>> User.objects.all()[2]
<User: qwe>
>>> User.objects.all()[2].password
u'pbkdf2_sha256$10000$HM2k6uDntJ68$DLqHKcGxtJG7pJC7tbZcm29vB88LEgaw2xroqZEkTFw='

So I have such a user and it's a valid account.

Upvotes: 0

Views: 2558

Answers (2)

Tadeck
Tadeck

Reputation: 137290

Issue no. 1 - wrong login()

This is probably the problem:

login(request, form.get_user())

You already have a login function and it happens to be a view. I suppose you want to confirm user authentication (form.is_valid() does not do that automatically).

More details are in the documentation of auth module:

How to log a user in

If you have an authenticated user you want to attach to the current session - this is done with a login() function.

login()

To log a user in, from a view, use login(). It takes an HttpRequest object and a User object. login() saves the user’s ID in the session, using Django’s session framework.

Note that any data set during the anonymous session is retained in the session after a user logs in.

This example shows how you might use both authenticate() and login():

from django.contrib.auth import authenticate, login

def my_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(username=username, password=password)
    if user is not None:
        if user.is_active:
            login(request, user)
            # Redirect to a success page.
        else:
            # Return a 'disabled account' error message
    else:
        # Return an 'invalid login' error message.

Issue no. 2 - wrong password

As Paulo mentioned, AuthenticationForm already handles password hashing. Please read the official documentation for examples:

Using the Django authentication system: Authentication in Web requests

Upvotes: 0

Paulo Bu
Paulo Bu

Reputation: 29794

I'm pretty sure you don't need to call make_password in this one:

if 'password' in post:
    post['password'] = make_password(post['password'])
form = AuthenticationForm(data=post)

Just pass the normal request.POST to data and the form itself do the encryption and test it against the database. This is the fragment of AuthenticationForm's clean method where it do this:

def clean(self):
    username = self.cleaned_data.get('username')
    password = self.cleaned_data.get('password')

    if username and password:
        self.user_cache = authenticate(username=username,
                                       password=password)
    ...

You can see the whole definition here.

I suppose your using official make_password function from django.contrib,auth but take a look at the docs closely, normally, user register functions do this automatically so you won't have to do it.

Anyways:

Check the errors form is yielding after is_valid call and change your login code to this:

if request.method == 'POST':
    form = AuthenticationForm(data=request.POST)

Hope this helps!

Upvotes: 2

Related Questions