Manual user registration without password

Hope you can help me make the best way to implement a manual (server initiated) login without using a password. Let me explain the workflow:

  • User registers
  • Thank! Activation link email was sent by blablabla
  • (The account exists, but it is not included)
  • User opens email, clicks link
  • (Account enabled)
  • Thank! Now you can use the site

What I'm trying to do is log in after he clicked the email link to start using the website right away.

I can’t use his password, since it is encrypted in the database, is it the only way to write my own authentication backup?

+59
django login django-authentication email-confirmation
May 7 '10 at 9:55 a.m.
source share
5 answers

You do not need a password to log in. The auth.login function simply takes a User object, which you probably already get from the database when you turn on the account. That way you can pass this directly for login to login .

Of course, you need to be very careful that the user cannot fake a link to an existing, already activated account, which would automatically register him as that user.

 from django.contrib.auth import login def 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 by:

Hmm, I didn’t notice that the requirement to use authenticate due to the additional property that it adds. Looking at the code, all it does is a backend attribute equivalent to the path to the authenticating backend module. So you can just fake it - before you log in, do the following:

 user.backend = 'django.contrib.auth.backends.ModelBackend' 
+83
May 7 '10 at 10:12
source share

Daniel answers very well.

Another way to do this is to create a HashModelBackend after the Custom Authorization backend https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#writing-an-authentication-backend as follows:

 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 set this in your settings:

 AUTHENTICATION_BACKENDS = ( 'myproject.backends.HashModelBackend', 'django.contrib.auth.backends.ModelBackend', ) 

Then your view will 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 
+25
May 7 '10 at 11:12
source share

Starting with Django 1.10, the process has been simplified.

In all versions of Django, for the user to be able to log in, he must be authenticated with one of the backends of your application (controlled by the AUTHENTICATION_BACKENDS parameter).

If you just want to force a login, you can simply state that the user has been authenticated by the first backend from this list:

 from django.conf import settings from django.contrib.auth import login # Django 1.10+ login(request, user, backend=settings.AUTHENTICATION_BACKENDS[0]) # Django <1.10 - fake the authenticate() call user.backend = settings.AUTHENTICATION_BACKENDS[0] login(request, user) 
+21
Sep 07 '16 at 7:47
source share

You can use the ska package, which implements login without entering Django without a password. ska works with authentication tokens, and its security is based on SHARED_KEY, which should be the same for all parties involved (servers).

On the client side (the side that requests a login without a password), you generate a URL and sign it using ska . Example:

 from ska import sign_url from ska.contrib.django.ska.settings import SECRET_KEY server_ska_login_url = 'https://server-url.com/ska/login/' signed_url = sign_url( auth_user='test_ska_user_0', secret_key=SECRET_KEY, url=server_ska_login_url extra={ 'email': 'john.doe@mail.example.com', 'first_name': 'John', 'last_name': 'Doe', } ) 

The default token expiration time is 600 seconds. You can tweak this by proving a lifetime argument.

On the server side (the site where users are logged in), bearing in mind that you installed ska correctly, the user logs in after visiting the URL, if it exists (username match) or is otherwise created. There are 3 callbacks that you can configure in the Django settings of your project.

  • USER_GET_CALLBACK (string): triggered if the user was successfully retrieved from the database (existing user).
  • USER_CREATE_CALLBACK (string): fires immediately after the user is created (the user does not exist).
  • USER_INFO_CALLBACK (string): USER_INFO_CALLBACK when authentication USER_INFO_CALLBACK .

See the documentation ( http://pythonhosted.org/ska/ ) for more information.

+2
Dec 21 '13 at 3:18
source share

The answer is given an answer.

The way to record your backend:

 from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend class HashModelBackend(ModelBackend): def authenticate(self, username=None, **kwargs): UserModel = get_user_model() if username is None: username = kwargs.get(UserModel.USERNAME_FIELD) try: user = UserModel._default_manager.get_by_natural_key(username) return user except UserModel.DoesNotExist: return None 

The answer is based on django.contrib.auth.backends.ModelBackend source code. This is relevant for django 1.9

And I would prefer to place a custom backend below the standard django:

 AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'yours.HashModelBackend', ] 

because account activation is less possible than the account itself. According to https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#specifying-authentication-backends :

The order AUTHENTICATION_BACKENDS matters, so if the same username and password are valid in multiple backends, Django will stop processing in the first positive match.

Be careful this code will authenticate your users even with the wrong passwords.

+2
May 26 '16 at 8:13
source share



All Articles