The authentication that comes with Django is good enough for most common cases, but you may have needs not met by the out-of-the-box defaults. To customize authentication to your projects needs involves understanding what points of the provided system are extensible or replaceable.
Authentication backends provide an extensible system for when a username and password stored with the User model need to be authenticated against a different service than Django’s default. You can give your models custom permissions that can be checked through Django’s authorization system. You can extend the default User model, or substitute a completely customized model.
There may be times you have the need to hook into another authentication source – that is, another source of usernames and passwords or authentication methods.
For example, your company may already have an LDAP setup that stores a username and password for every employee. It’d be a hassle for both the network administrator and the users themselves if users had separate accounts in LDAP and the Django-based applications.
So, to handle situations like this, the Django authentication system lets you plug in other authentication sources. You can override Django’s default database-based scheme, or you can use the default system in tandem with other systems.
Behind the scenes, Django maintains a list of authentication backends that it checks for authentication. When somebody calls
authenticate() – as described in the previous section on logging a user in – Django tries authenticating across all of its authentication backends. If the first authentication method fails,
Django tries the second one, and so on, until all backends have been attempted.
The list of authentication backends to use is specified in the
AUTHENTICATION_BACKENDS setting. This should be a list of Python path names that point to Python classes that know how to authenticate. These classes can be anywhere on your Python path. By default,
is set to:
That’s the basic authentication backend that checks the Django users database and queries the built-in permissions. It does not provide protection against brute force attacks via any rate limiting mechanism. You may either implement your own rate limiting mechanism in a custom authorization backend, or use the mechanisms provided by most Web servers. The order of
AUTHENTICATION_BACKENDS matters, so if the same username and password is valid in multiple backends, Django will stop processing at the first positive match. If a backend raises a
PermissionDenied exception, authentication will immediately fail. Django won’t check the backends that follow.
Once a user has authenticated, Django stores which backend was used to authenticate the user in the user’s session, and re-uses the same backend for the duration of that session whenever access to the currently authenticated user is needed. This effectively means that authentication sources are cached on a per-session basis, so if you change
AUTHENTICATION_BACKENDS, you’ll need to clear out session data if you need to force users to re-authenticate using different methods. A simple way to do that is simply to execute
An authentication backend is a class that implements two required methods:
authenticate(**credentials), as well as a set of optional permission related authorization methods. The
get_user method takes a
user_id – which could be a username, database ID or whatever, but has to be the primary key of your
User object – and returns a
User object. The
authenticate method takes credentials as keyword arguments. Most of the time, it’ll just look like this:
But it could also authenticate a token, like so:
authenticate should check the credentials it gets, and it should return a
User object that matches those credentials, if the credentials are valid. If they’re not valid, it should return
The Django admin system is tightly coupled to the Django
User object described at the beginning of this chapter.
For now, the best way to deal with this is to create a Django
User object for each user that exists for your backend (e.g., in your LDAP directory, your external SQL database, etc.) You can either write a script to do this in advance, or your
authenticate method can do it the first time a user logs in.
Here’s an example backend that authenticates against a username and password variable defined in your
settings.py file and creates a Django
User object the first time a user authenticates:
Custom authorization backends can provide their own permissions. The user model will delegate permission lookup functions (
has_module_perms()) to any authentication backend that implements these functions. The permissions given to the user will be the superset of all permissions returned by all backends. That is, Django grants a permission to a user that any one backend grants.
If a backend raises a
PermissionDenied exception in
has_module_perms(), the authorization will immediately fail and Django won’t check the backends that follow. The simple backend above could implement permissions for the admin fairly simply:
This gives full permissions to the user granted access in the above example. Notice that in addition to the same arguments given to the associated
User functions, the backend authorization functions all take the user object, which may be an anonymous user, as an argument.
A full authorization implementation can be found in the
ModelBackend class in
django/contrib/auth/backends.py, which is the default backend and it queries the
auth_permission table most of the time. If you wish to provide custom behavior for only part of the backend API, you can take advantage of Python inheritance and subclass
ModelBackend instead of implementing the complete API in a custom backend.
An anonymous user is one that is not authenticated i.e. they have provided no valid authentication details. However, that does not necessarily mean they are not authorized to do anything. At the most basic level, most Web sites authorize anonymous users to browse most of the site, and many allow anonymous posting of comments etc.
Django’s permission framework does not have a place to store permissions for anonymous users. However, the user object passed to an authentication backend may be an
django.contrib.auth.models.AnonymousUser object, allowing the backend to specify custom authorization behavior for anonymous users.
This is especially useful for the authors of re-usable apps, who can delegate all questions of authorization to the auth backend, rather than needing settings, for example, to control anonymous access.
An inactive user is a one that is authenticated but has its attribute
is_active set to
False. However, this does not mean they are not authorized to do anything. For example, they are allowed to activate their account.
The support for anonymous users in the permission system allows for a scenario where anonymous users have permissions to do something while inactive authenticated users do not. Do not forget to test for the
is_active attribute of the user in your own backend permission methods.
Django’s permission framework has a foundation for object permissions, though there is no implementation for it in the core. That means that checking for object permissions will always return
False or an empty list (depending on the check performed). An authentication backend will receive the keyword parameters
user_obj for each object related authorization method and can return the object level permission as appropriate.
To create custom permissions for a given model object, use the
permissions model Meta attribute. This example Task model creates three custom permissions, i.e. actions users can or cannot do with Task instances, specific to your application:
The only thing this does is create those extra permissions when you run
manage.py migrate. Your code is in charge of checking the value of these permissions when a user is trying to access the functionality provided by the application (viewing tasks, changing the status of tasks, closing tasks.) Continuing the above example, the following checks if a user may view tasks:
There are two ways to extend the default
User model without substituting your own model. If the changes you need are purely behavioral, and don’t require any change to what is stored in the database, you can create a proxy model based on
User. This allows for any of the features offered by proxy models including default ordering, custom managers, or custom model methods.
If you wish to store information related to
User, you can use a one-to-one relationship to a model containing the fields for additional information. This one-to-one model is often called a profile model, as it might store non-auth related information about a site user. For example, you might create an Employee model:
Assuming an existing Employee Fred Smith who has both a User and Employee model, you can access the related information using Django’s standard related model conventions:
To add a profile model’s fields to the user page in the admin, define an
InlineModelAdmin (for this example, we’ll use a
StackedInline) in your app’s
admin.py and add it to a
UserAdmin class which is registered with the
These profile models are not special in any way – they are just Django models that happen to have a one-to-one link with a User model. As such, they do not get auto created when a user is created, but a
django.db.models.signals.post_save could be used to create or update related models as appropriate.
Note that using related models results in additional queries or joins to retrieve the related data, and depending on your needs substituting the User model and adding the related fields may be your better option. However existing links to the default User model within your project’s apps may justify the extra database load.
Some kinds of projects may have authentication requirements for which Django’s built-in
User model is not always appropriate. For instance, on some sites it makes more sense to use an email address as your identification token instead of a username. Django allows you to override the default User model by providing a value for the
AUTH_USER_MODEL setting that references a custom model:
This dotted pair describes the name of the Django app (which must be in your
INSTALLED_APPS), and the name of the Django model that you wish to use as your User model.
Notwithstanding the warning above, Django does fully support custom user models, however a full explanation is beyond the scope of this book. A full example of an admin-compliant custom user app, as well as comprehensive documentation on custom user models can be found on the Django Project website.
In this chapter, we have learned about user authentication in Django, the built-in authentication tools, as well as the wide range of customizations available. In the next chapter we will be covering arguably the most important tool for creating and maintaining robust applications – automated testing.