1

I have written the following class for Auth Back end and placed it inside a file "authentication.py" inside the app directory:

from events.models import User

class authBackend():
    def authenticate(self, request, username, passwprd):
        try:
            user = User.objects.get(rollNo=username)
            success = user.check_password(password)
            if success:
                return user
        except User.DoesNotExist:
            pass
        return None

    def get_user(self, uid):
        try:
            return User.objects.get(pk=Uid)
        except:
            return None

then i added (or at least i thought i did) it to settings.py:

AUTHENTICATION_BACKENDS = [
    'events.authentication'
]

this is how i am logging in the user:

def login_view(request):
    if request.method == "POST":

        # Attempt to sign user in
        rollno = request.POST["rollno"]
        password = request.POST["password"]

        user = authenticate(request, username=rollno, password=password)

        # Check if authentication successful
        if user is not None:
            login(request, user)
            return HttpResponseRedirect(reverse("events:index"))
        else:
            return render(request, "events/login.html", {
                "message": "Invalid roll number and/or password."
            })
    else:
        return render(request, "events/login.html")

But i am getting the following trace back:

ImportError at /login Module "events" does not define a "authentication" attribute/class

I am a noob and i am pretty sure i am doing something wrong, i just don't understand what it is.

Can someone please tell me how to do it right?

  • It should be `'events.authentication.authBackend'` – Abdul Aziz Barkat Feb 27 '21 at 09:15
  • @AbdulAzizBarkat Thank you for your reply, yeah, i realized i need to import the class not the file, but can you please check if there's something wrong with my Back end and my login_view? – Apoorva Shridhar Feb 27 '21 at 09:23
  • @ApoorvaShridhar: it probably is better to start with the `BaseBackend`, or even the `ModelBackend`, since the backend should also implement `get_user_permissions`, `get_group_permissions`, `get_all_permissions` and `has_perms`. – Willem Van Onsem Feb 27 '21 at 09:26
  • @AbdulAzizBarkat Actually, i am unable to log in any user, it just returns None – Apoorva Shridhar Feb 27 '21 at 09:26
  • @ApoorvaShridhar: you also made a typo in the parameter names: it is `password`, not `passwprd` – Willem Van Onsem Feb 27 '21 at 09:27
  • @WillemVanOnsem sorry about the typo, i had already corrected that in my original code – Apoorva Shridhar Feb 27 '21 at 09:30
  • @ApoorvaShridhar all of the above plus the backend shouldn't directly import the user model (it should be reusable) you should use [`django.contrib.auth.get_user_model`](https://docs.djangoproject.com/en/3.1/topics/auth/customizing/#django.contrib.auth.get_user_model) to get the user model. – Abdul Aziz Barkat Feb 27 '21 at 09:31

1 Answers1

2

You need to import it with the class name as well, so:

AUTHENTICATION_BACKENDS = [
    'events.authentication.authBackend'
]

In your authBackend, you also made a number of mistakes. First of all the authentication backend needs to implement a number of functions [Django-doc]:

The user model and its manager will delegate permission lookup functions (get_user_permissions(), get_group_permissions(), get_all_permissions(), has_perm(), has_module_perms(), and with_perm()) to any authentication backend that implements these functions.

You thus will need to implement this functions as well. Therefore it might be better to inherit from the BaseBackend [Django-doc] or perhaps even better from the ModelBackend, since that will already implement the logic, and you thus only need to override certain functions to let it work with your new model.

You also made a typo in the parameter names: it is password, not passwprd:

from django.contrib.auth.backends import BaseBackend
from events.models import User

class authBackend(BaseBackend):
    def authenticate(self, request, username, password):
        try:
            user = User.objects.get(rollNo=username)
            success = user.check_password(password)
            if success:
                return user
        except User.DoesNotExist:
            pass
        return None

    def get_user(self, uid):
        try:
            return User.objects.get(pk=Uid)
        except:
            return None

Note: According to the PEP-8 Style guide [pep-0008], class names are written in PerlCase starting with an uppercase, so you might want to consider renaming authBackend to AuthBackend.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • I am still unable to login users using the login_view, there are two things i think are going wrong here, one is that i probably need to import the authenticate function in my views as well, and second is, i probably did something wrong with implementing the back end(sorry if it seems like a stupid question i am a beginner) – Apoorva Shridhar Feb 27 '21 at 09:33
  • @ApoorvaShridhar: you did not import the authenticate function in your view? – Willem Van Onsem Feb 27 '21 at 09:35
  • "from events.authentication import authBackend" and while using "user = authBackend.authenticate(request, username=rollno, password=password)" Is this the correct way to do it? – Apoorva Shridhar Feb 27 '21 at 09:42
  • @ApoorvaShridhar `from django.contrib.auth import authenticate` – Abdul Aziz Barkat Feb 27 '21 at 09:43
  • @ApoorvaShridhar: no, the idea is that you have a loose coupling with the backend, so `from django.contrib.auth import authenticate`. Furthermore that would not work at all, since `request` is then passed to the `self` parameter. – Willem Van Onsem Feb 27 '21 at 09:43
  • @WillemVanOnsem i imported it that way. I am giving the correct values of "rollNo" field and the "password" field, but authenticate still returns None. https://pastebin.com/abvhhu2Z this is my User model, is there something wrong there? – Apoorva Shridhar Feb 27 '21 at 09:50
  • @ApoorvaShridhar: the password is hashed in the database? Did you fix the typo in the `password` parameter? – Willem Van Onsem Feb 27 '21 at 09:52
  • @ApoorvaShridhar in `create_superuser` you don't set the password properly. Do it similar to how you do in `create_user` – Abdul Aziz Barkat Feb 27 '21 at 09:54
  • @ApoorvaShridhar: you should use `.set_password` to make sure that the password is properly hashed. – Willem Van Onsem Feb 27 '21 at 09:55
  • @WillemVanOnsem, nope it's not working. I can register a new user, i can check that the user has been created using the shell, but i can't authenticate and login the user. I am stuck – Apoorva Shridhar Feb 27 '21 at 10:42
  • @ApoorvaShridhar: but does your *database* contains the *hashed* passwords, or the *raw* passwords... – Willem Van Onsem Feb 27 '21 at 10:43
  • @WillemVanOnsem it still contains the raw passwords. I used set_password while creating the user in my register view: "user = User.objects.create_user(email, username, year, branch, rollno, password) user.set_password(user.password) user.save()" – Apoorva Shridhar Feb 27 '21 at 10:48
  • @ApoorvaShridhar: but normally the `create_user` will hash these, so you should not use `user.set_password(user.password)`, since then you are hashing a *second* time. – Willem Van Onsem Feb 27 '21 at 10:52
  • @WillemVanOnsem yes now it's showing hashed passwords. But do i also need to re write the login method? https://pastebin.com/DMyqKEez This is my login view basically"login(request, user)". It's now redirecting to the "success_url" as it should, nor is it giving me the error message, so that means that authenticate method is working. But the user is still not logged in. Do i need to re implement "login" as well? – Apoorva Shridhar Feb 27 '21 at 11:47
  • @WillemVanOnsem I can't login to django admin interface either – Apoorva Shridhar Feb 27 '21 at 12:17
  • 1
    @WillemVanOnsem i resolved the issue. Thank you very much, you have been a huge help, thanks – Apoorva Shridhar Feb 28 '21 at 15:00