django authentication without a password
Asked Answered
D

4

29

I'm using the default authentication system with django, but I've added on an OpenID library, where I can authenticate users via OpenID. What I'd like to do is log them in, but it seems using the default django auth system, I need their password to authenticate the user. Is there a way to get around this without actually using their password?

I'd like to do something like this...

user = ... # queried the user based on the OpenID response
user = authenticate(user) # function actually requires a username and password
login(user)

I sooner just leave off the authenticate function, but it attaches a backend field, which is required by login.

Decretal answered 2/7, 2011 at 23:34 Comment(1)
Possible duplicate of Manually logging in a user without password.Sprint
R
28

It's straightforward to write a custom authentication backend for this. If you create yourapp/auth_backend.py with the following contents:

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User


class PasswordlessAuthBackend(ModelBackend):
    """Log in to Django without providing a password.

    """
    def authenticate(self, username=None):
        try:
            return User.objects.get(username=username)
        except User.DoesNotExist:
            return None

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

Then add to your settings.py:

AUTHENTICATION_BACKENDS = (
    # ... your other backends
    'yourapp.auth_backend.PasswordlessAuthBackend',
)

In your view, you can now call authenticate without a password:

user = authenticate(username=user.username)
login(request, user)
Rockrose answered 21/1, 2014 at 16:11 Comment(5)
This works great but beware - if you want to use regular auth in some situations, as well as no-password auth in others, be sure to prevent your new backend causing every attempt with a valid username to succeed - remember that all backends are tried when authenticate() is called. In mine I require a special token argument to be included to ensure that the caller of authenticate() really wanted no-password auth to work.Commutual
@Commutual How you implemented regular auth and no password auth. I am trying to implement that but it is calling regular auth method.Intricate
Above code is not working with Django 2.1. It is not calling authenticate method of PasswordlessAuthBackend class. But it worls with Django 2.0Intricate
@SanketPatel I suspect that in newer Django versions the def authenticate must take a request parameter, as in another answer for this question.Garate
@SanketPatel More info in https://mcmap.net/q/261239/-how-to-access-the-request-in-a-django-custom-authentication-backend.Garate
A
8

This is a bit of a hack but if you don't want to rewrite a bunch of stuff remove the authenticate

user.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, user)

user would be your User object

Allowed answered 5/7, 2011 at 4:45 Comment(3)
That is one possible solution, but that doesn't get stored in the session, so if you open a new tab and go to the site, you have to log in again.Decretal
This WILL be saved in the session, and work in subsequent views. The only gotcha is that the backend you set must be included in the AUTHENTICATION_BACKENDS setting. I wish I could undo my downvote, but I can't.Hermanhermann
@voodoogiant, I met exactly the same issue, that is the session is not stored. But weird enough, the first 2 XHR requests could get session data from session-id correctly. But the later XHR request does not, and Django server set session-id in cookie to blank string in response. Do you know why? and how to solve that?Kobarid
R
7

In order to do authenticate without password, in your settings.py:

AUTHENTICATION_BACKENDS = [
# auth_backend.py implementing Class YourAuth inside yourapp folder
    'yourapp.auth_backend.YourAuth', 
# Default authentication of Django
    'django.contrib.auth.backends.ModelBackend',
]

In your auth_backend.py:

NOTE: If you have custom model for your app then import from .models CustomUser

from .models import User 
from django.conf import settings

# requires to define two functions authenticate and get_user

class YourAuth:  

    def authenticate(self, request, username=None):
        try:
            user = User.objects.get(username=username)
            return user
        except User.DoesNotExist:
            return None
        
    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

In your Views for custom login request:

# Your Logic to login user
userName = authenticate(request, username=uid)
login(request, userName)

For further reference, use the django documentation here.

Regardful answered 18/3, 2019 at 9:7 Comment(5)
Thanks for formatting for better readability @OliviaStorkRegardful
can I use this on just one app of my project, and not apply it to the rest of the project?Torin
'uid' is not defined. What are you refering to with 'uid'?Starfish
'uid' is the custom parameter to store User ID in logicRegardful
@Torin Yes you can make custom user modelRegardful
Z
2

You can easily fix this by creating your own authentication backend and adding it to the AUTHENTICATION_BACKENDS setting.

There are some OpenID backends available already, so with a bit of searching you could save yourself the trouble of writing one.

Zygodactyl answered 2/7, 2011 at 23:58 Comment(2)
I've had problems with django OpenID backends as they weren't compatible with Google's unique way of doing OpenID. Anyway, like I said I already have a password-based backend and I just want to use OpenID in some cases--not switch to a strict OpenID backend.Decretal
@voodoogiant: depending on the keyword arguments the authentication backend is chosen. So if you use openid_token for your OpenID backend and username with password for your normal authentication system than they will both work.Zygodactyl

© 2022 - 2024 — McMap. All rights reserved.