Manually logging in a user without password
You don't need a password to log a user in. The auth.login
function just takes a User
object, which you are presumably already getting from the database when you enable the account. So you can pass that straight to login
.
Of course, you'll need to be very careful that there's no way a user can spoof a link to an existing already-enabled account, which would then automatically log them in as that user.
from django.contrib.auth import logindef activate_account(request, hash): account = get_account_from_hash(hash) if not account.is_active: account.activate() account.save() user = account.user login(request, user)
... etc.
Edited:
Hmm, didn't notice that requirement to use authenticate
because of the extra property it adds. Looking at the code, all it does is a backend
attribute equivalent to the module path of the authenticating backend. So you could just fake it - before the login call above, do this:
user.backend = 'django.contrib.auth.backends.ModelBackend'
As of Django 1.10, the process has been simplified.
In all versions of Django, in order for a user to be logged in, they must be authenticated by one of your app's backends (controlled by the AUTHENTICATION_BACKENDS
setting).
If you simply want to force a login, you can just claim that the user was authenticated by the first backend from that list:
from django.conf import settingsfrom django.contrib.auth import login# Django 1.10+login(request, user, backend=settings.AUTHENTICATION_BACKENDS[0])# Django <1.10 - fake the authenticate() calluser.backend = settings.AUTHENTICATION_BACKENDS[0]login(request, user)
Daniel's answer is very good.
Another way to do it is to create a HashModelBackend following the Custom Authorization backends https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#writing-an-authentication-backend like this:
class HashModelBackend(object): def authenticate(self, hash=None): user = get_user_from_hash(hash) return user def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None
And then install this in your settings:
AUTHENTICATION_BACKENDS = ( 'myproject.backends.HashModelBackend', 'django.contrib.auth.backends.ModelBackend',)
Then your view would be something like this:
def activate_account(request, hash): user = authenticate(hash=hash) if user: # check if user is_active, and any other checks login(request, user) else: return user_not_found_bad_hash_message