Code


Version 5 (modified by lukesneeringer, 10 months ago) (diff)

Documenting the idea to have email user live in d.c.auth

Adding an Email-based authentication model

ContribAuthImprovements described and implemented a set of changes to allow for pluggable User models in contrib.auth. One of the primary motivators behind this change was to make it easy to implement email-based authentication. To make this even easier, #20824 describes an enhancement for Django to ship with a ready-to-use Email-based login model.

Some django-developer discussions that cover this topic:

A number of solutions have been proposed. Here is a summary of the most viable candidates:

Option 1: Simple auth.User analog

Feature branch: https://github.com/tanderegg/django/tree/ticket_20824_master

This option is a simple analog to the auth.User model. In auth_email.models, there is an AbstractUser class that inherits from AbstractBaseUser and PermissionsMixin, and contains the fields email, first_name, last_name, is_active, and is_staff, basically identical to auth.User with the exception of having no username. the auth_email.models.User class then extends the AbstractUser class to make it instantiable and swappable. A custom UserManager class adds in methods for creating users and superusers.

The auth_email.admin.UserAdmin class inherits from auth.admin.UserAdmin and overides the appropriate members and methods, including pointing the class to the custom UserCreationForm and UserChangeForm in auth_email.forms. These forms are again nearly identical to the ones in auth.forms.

The approach I took is very similar to the one used in https://github.com/Liberationtech/django-libtech-emailuser. The primary difference is that django-libtech-emailuser does not contain a new abstract class, and instead contains a single concrete class EmailUser.

Note: A potential spinoff of this option would be to include the EmailUser model (and anything else necessary to support it) in the django.contrib.auth app. In this case, we'd have to write a rule into our model detection that basically says that if a model is subclasses AbstractBaseUser, include it in the app if and only if it is the value of the AUTH_USER_MODEL setting. This addresses the second "disadvantage" listed below, but adds more code.

Advantages

  • Simple implementation, a developer must only include auth_email in INSTALLED_APPS and set AUTH_USER_MODEL = 'auth_email.User'.
  • Principle of least surprise: auth_email.User should behave exactly as auth.User would, with the exception of no username.
  • A small amount of new code means fewer opportunities to introduce new bugs.
  • Makes few assumptions about how an email user should behave, which leaves further implementation up to each use case

Problems

  • django.contrib.auth could potentially be modified a bit to reduce code duplication, specifically with regards to admin.UserAdmin. If there is interest in this I will modify my branch.
  • Requires installing an additional app besides django.contrib.auth.

Option 2: The authtools approach

This option is similar to https://django-authtools.readthedocs.org/en/latest/. The idea would be to create a separate app that houses admin, views, etc., that are analogous to the ones that support User in django.contrib.auth.

Advantages

  • Allows for other, potentially more sweeping alterations if desired (e.g. authtools combines first_name and last_name).

Disadvantages

  • More code duplication
  • Doesn't really follow principle of least surprise. Ideally, the email-based User should behave exactly like the stock User, with this one exception.

Final decision

To be determined.