123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170 |
- ====================================
- Customizing authentication in Django
- ====================================
- 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. This document provides details
- about how the auth system can be customized.
- :ref:`Authentication backends <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 :ref:`custom permissions <custom-permissions>` that
- can be checked through Django's authorization system.
- You can :ref:`extend <extending-user>` the default ``User`` model, or
- :ref:`substitute <auth-custom-user>` a completely customized model.
- .. _authentication-backends:
- Other authentication sources
- ============================
- 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.
- See the :ref:`authentication backend reference
- <authentication-backends-reference>` for information on the authentication
- backends included with Django.
- Specifying authentication backends
- ----------------------------------
- Behind the scenes, Django maintains a list of "authentication backends" that it
- checks for authentication. When somebody calls
- :func:`django.contrib.auth.authenticate()` -- as described in :ref:`How to log
- a user in <how-to-log-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
- :setting:`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, :setting:`AUTHENTICATION_BACKENDS` is set to::
- ['django.contrib.auth.backends.ModelBackend']
- 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 auth backend, or use the
- mechanisms provided by most Web servers.
- The order of :setting:`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 :class:`~django.core.exceptions.PermissionDenied`
- exception, authentication will immediately fail. Django won't check the
- backends that follow.
- .. note::
- 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
- :setting:`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 ``Session.objects.all().delete()``.
- Writing an authentication backend
- ---------------------------------
- An authentication backend is a class that implements two required methods:
- ``get_user(user_id)`` and ``authenticate(request, **credentials)``, as well as
- a set of optional permission related :ref:`authorization methods
- <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 a ``request`` argument and credentials as
- keyword arguments. Most of the time, it'll just look like this::
- class MyBackend(object):
- def authenticate(self, request, username=None, password=None):
- # Check the username/password and return a user.
- ...
- But it could also authenticate a token, like so::
- class MyBackend(object):
- def authenticate(self, request, token=None):
- # Check the token and return a user.
- ...
- Either way, ``authenticate()`` should check the credentials it gets and return
- a user object that matches those credentials if the credentials are valid. If
- they're not valid, it should return ``None``.
- ``request`` is an :class:`~django.http.HttpRequest` and may be ``None`` if it
- wasn't provided to :func:`~django.contrib.auth.authenticate` (which passes it
- on to the backend).
- The Django admin is tightly coupled to the Django :ref:`User object
- <user-objects>`. 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::
- from django.conf import settings
- from django.contrib.auth.hashers import check_password
- from django.contrib.auth.models import User
- class SettingsBackend(object):
- """
- Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.
- Use the login name and a hash of the password. For example:
- ADMIN_LOGIN = 'admin'
- ADMIN_PASSWORD = 'pbkdf2_sha256$30000$Vo0VlMnkR4Bk$qEvtdyZRWTcOsCnI/oQ7fVOu1XAURIZYoOZ3iq8Dr4M='
- """
- def authenticate(self, request, username=None, password=None):
- login_valid = (settings.ADMIN_LOGIN == username)
- pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
- if login_valid and pwd_valid:
- try:
- user = User.objects.get(username=username)
- except User.DoesNotExist:
- # Create a new user. There's no need to set a password
- # because only the password from settings.py is checked.
- user = User(username=username)
- user.is_staff = True
- user.is_superuser = True
- user.save()
- return user
- return None
- def get_user(self, user_id):
- try:
- return User.objects.get(pk=user_id)
- except User.DoesNotExist:
- return None
- .. versionchanged:: 1.11
- The ``request`` parameter was added to ``authenticate()`` and support for
- backends that don't accept it will be removed in Django 2.1.
- .. _authorization_methods:
- Handling authorization in custom backends
- -----------------------------------------
- Custom auth backends can provide their own permissions.
- The user model will delegate permission lookup functions
- (:meth:`~django.contrib.auth.models.User.get_group_permissions()`,
- :meth:`~django.contrib.auth.models.User.get_all_permissions()`,
- :meth:`~django.contrib.auth.models.User.has_perm()`, and
- :meth:`~django.contrib.auth.models.User.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 :class:`~django.core.exceptions.PermissionDenied`
- exception in :meth:`~django.contrib.auth.models.User.has_perm()` or
- :meth:`~django.contrib.auth.models.User.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 magic admin
- fairly simply::
- class SettingsBackend(object):
- ...
- def has_perm(self, user_obj, perm, obj=None):
- return user_obj.username == settings.ADMIN_LOGIN
- 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
- :class:`django.contrib.auth.models.User` functions, the backend auth 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 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.
- .. _django/contrib/auth/backends.py: https://github.com/django/django/blob/master/django/contrib/auth/backends.py
- .. _anonymous_auth:
- Authorization for anonymous users
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 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 websites
- 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 :class:`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.
- .. _inactive_auth:
- Authorization for inactive users
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- An inactive user is a one that has its
- :attr:`~django.contrib.auth.models.User.is_active` field set to ``False``. The
- :class:`~django.contrib.auth.backends.ModelBackend` and
- :class:`~django.contrib.auth.backends.RemoteUserBackend` authentication
- backends prohibits these users from authenticating. If a custom user model
- doesn't have an :attr:`~django.contrib.auth.models.CustomUser.is_active` field,
- all users will be allowed to authenticate.
- You can use :class:`~django.contrib.auth.backends.AllowAllUsersModelBackend`
- or :class:`~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend` if you
- want to allow inactive users to authenticate.
- 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.
- .. versionchanged:: 1.10
- In older versions, the :class:`~django.contrib.auth.backends.ModelBackend`
- allowed inactive users to authenticate.
- Handling object permissions
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 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 ``obj`` and ``user_obj`` for each object related authorization
- method and can return the object level permission as appropriate.
- .. _custom-permissions:
- Custom permissions
- ==================
- To create custom permissions for a given model object, use the ``permissions``
- :ref:`model Meta attribute <meta-options>`.
- This example Task model creates three custom permissions, i.e., actions users
- can or cannot do with Task instances, specific to your application::
- class Task(models.Model):
- ...
- class Meta:
- permissions = (
- ("view_task", "Can see available tasks"),
- ("change_task_status", "Can change the status of tasks"),
- ("close_task", "Can remove a task by setting its status as closed"),
- )
- The only thing this does is create those extra permissions when you run
- :djadmin:`manage.py migrate <migrate>` (the function that creates permissions
- is connected to the :data:`~django.db.models.signals.post_migrate` signal).
- 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::
- user.has_perm('app.view_task')
- .. _extending-user:
- Extending the existing ``User`` model
- =====================================
- There are two ways to extend the default
- :class:`~django.contrib.auth.models.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 :ref:`proxy model
- <proxy-models>` based on :class:`~django.contrib.auth.models.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
- :class:`~django.db.models.OneToOneField` 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::
- from django.contrib.auth.models import User
- class Employee(models.Model):
- user = models.OneToOneField(User, on_delete=models.CASCADE)
- department = models.CharField(max_length=100)
- 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::
- >>> u = User.objects.get(username='fsmith')
- >>> freds_department = u.employee.department
- To add a profile model's fields to the user page in the admin, define an
- :class:`~django.contrib.admin.InlineModelAdmin` (for this example, we'll use a
- :class:`~django.contrib.admin.StackedInline`) in your app's ``admin.py`` and
- add it to a ``UserAdmin`` class which is registered with the
- :class:`~django.contrib.auth.models.User` class::
- from django.contrib import admin
- from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
- from django.contrib.auth.models import User
- from my_user_profile_app.models import Employee
- # Define an inline admin descriptor for Employee model
- # which acts a bit like a singleton
- class EmployeeInline(admin.StackedInline):
- model = Employee
- can_delete = False
- verbose_name_plural = 'employee'
- # Define a new User admin
- class UserAdmin(BaseUserAdmin):
- inlines = (EmployeeInline, )
- # Re-register UserAdmin
- admin.site.unregister(User)
- admin.site.register(User, UserAdmin)
- 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 aren't
- auto created when a user is created, but
- a :attr:`django.db.models.signals.post_save` could be used to create or update
- related models as appropriate.
- Using related models results in additional queries or joins to retrieve the
- related data. Depending on your needs, a custom user model that includes the
- related fields may be your better option, however, existing relations to the
- default user model within your project's apps may justify the extra database
- load.
- .. _auth-custom-user:
- Substituting a custom ``User`` model
- ====================================
- Some kinds of projects may have authentication requirements for which Django's
- built-in :class:`~django.contrib.auth.models.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 :setting:`AUTH_USER_MODEL` setting that references a custom model::
- AUTH_USER_MODEL = 'myapp.MyUser'
- This dotted pair describes the name of the Django app (which must be in your
- :setting:`INSTALLED_APPS`), and the name of the Django model that you wish to
- use as your user model.
- Using a custom user model when starting a project
- -------------------------------------------------
- If you're starting a new project, it's highly recommended to set up a custom
- user model, even if the default :class:`~django.contrib.auth.models.User` model
- is sufficient for you. This model behaves identically to the default user
- model, but you'll be able to customize it in the future if the need arises::
- from django.contrib.auth.models import AbstractUser
- class User(AbstractUser):
- pass
- Don't forget to point :setting:`AUTH_USER_MODEL` to it. Do this before creating
- any migrations or running ``manage.py migrate`` for the first time.
- Changing to a custom user model mid-project
- -------------------------------------------
- Changing :setting:`AUTH_USER_MODEL` after you've created database tables is
- significantly more difficult since it affects foreign keys and many-to-many
- relationships, for example.
- This change can't be done automatically and requires manually fixing your
- schema, moving your data from the old user table, and possibly manually
- reapplying some migrations. See :ticket:`25313` for an outline of the steps.
- Due to limitations of Django's dynamic dependency feature for swappable
- models, the model referenced by :setting:`AUTH_USER_MODEL` must be created in
- the first migration of its app (usually called ``0001_initial``); otherwise,
- you'll have dependency issues.
- In addition, you may run into a ``CircularDependencyError`` when running your
- migrations as Django won't be able to automatically break the dependency loop
- due to the dynamic dependency. If you see this error, you should break the loop
- by moving the models depended on by your user model into a second migration.
- (You can try making two normal models that have a ``ForeignKey`` to each other
- and seeing how ``makemigrations`` resolves that circular dependency if you want
- to see how it's usually done.)
- Reusable apps and ``AUTH_USER_MODEL``
- -------------------------------------
- Reusable apps shouldn't implement a custom user model. A project may use many
- apps, and two reusable apps that implemented a custom user model couldn't be
- used together. If you need to store per user information in your app, use
- a :class:`~django.db.models.ForeignKey` or
- :class:`~django.db.models.OneToOneField` to ``settings.AUTH_USER_MODEL``
- as described below.
- Referencing the ``User`` model
- ------------------------------
- .. currentmodule:: django.contrib.auth
- If you reference :class:`~django.contrib.auth.models.User` directly (for
- example, by referring to it in a foreign key), your code will not work in
- projects where the :setting:`AUTH_USER_MODEL` setting has been changed to a
- different user model.
- .. function:: get_user_model()
- Instead of referring to :class:`~django.contrib.auth.models.User` directly,
- you should reference the user model using
- ``django.contrib.auth.get_user_model()``. This method will return the
- currently active user model -- the custom user model if one is specified, or
- :class:`~django.contrib.auth.models.User` otherwise.
- When you define a foreign key or many-to-many relations to the user model,
- you should specify the custom model using the :setting:`AUTH_USER_MODEL`
- setting. For example::
- from django.conf import settings
- from django.db import models
- class Article(models.Model):
- author = models.ForeignKey(
- settings.AUTH_USER_MODEL,
- on_delete=models.CASCADE,
- )
- When connecting to signals sent by the user model, you should specify
- the custom model using the :setting:`AUTH_USER_MODEL` setting. For example::
- from django.conf import settings
- from django.db.models.signals import post_save
- def post_save_receiver(sender, instance, created, **kwargs):
- pass
- post_save.connect(post_save_receiver, sender=settings.AUTH_USER_MODEL)
- Generally speaking, you should reference the user model with the
- :setting:`AUTH_USER_MODEL` setting in code that is executed at import
- time. ``get_user_model()`` only works once Django has imported all models.
- .. _specifying-custom-user-model:
- Specifying a custom user model
- ------------------------------
- .. admonition:: Model design considerations
- Think carefully before handling information not directly related to
- authentication in your custom user model.
- It may be better to store app-specific user information in a model
- that has a relation with the user model. That allows each app to specify
- its own user data requirements without risking conflicts with other
- apps. On the other hand, queries to retrieve this related information
- will involve a database join, which may have an effect on performance.
- Django expects your custom user model to meet some minimum requirements.
- #. If you use the default authentication backend, then your model must have a
- single unique field that can be used for identification purposes. This can
- be a username, an email address, or any other unique attribute. A non-unique
- username field is allowed if you use a custom authentication backend that
- can support it.
- #. Your model must provide a way to address the user in a "short" and
- "long" form. The most common interpretation of this would be to use
- the user's given name as the "short" identifier, and the user's full
- name as the "long" identifier. However, there are no constraints on
- what these two methods return - if you want, they can return exactly
- the same value.
- The easiest way to construct a compliant custom user model is to inherit from
- :class:`~django.contrib.auth.models.AbstractBaseUser`.
- :class:`~django.contrib.auth.models.AbstractBaseUser` provides the core
- implementation of a user model, including hashed passwords and tokenized
- password resets. You must then provide some key implementation details:
- .. currentmodule:: django.contrib.auth
- .. class:: models.CustomUser
- .. attribute:: USERNAME_FIELD
- A string describing the name of the field on the user model that is
- used as the unique identifier. This will usually be a username of some
- kind, but it can also be an email address, or any other unique
- identifier. The field *must* be unique (i.e., have ``unique=True`` set
- in its definition), unless you use a custom authentication backend that
- can support non-unique usernames.
- In the following example, the field ``identifier`` is used
- as the identifying field::
- class MyUser(AbstractBaseUser):
- identifier = models.CharField(max_length=40, unique=True)
- ...
- USERNAME_FIELD = 'identifier'
- :attr:`USERNAME_FIELD` now supports
- :class:`~django.db.models.ForeignKey`\s. Since there is no way to pass
- model instances during the :djadmin:`createsuperuser` prompt, expect the
- user to enter the value of :attr:`~django.db.models.ForeignKey.to_field`
- value (the :attr:`~django.db.models.Field.primary_key` by default) of an
- existing instance.
- .. attribute:: EMAIL_FIELD
- .. versionadded:: 1.11
- A string describing the name of the email field on the ``User`` model.
- This value is returned by
- :meth:`~models.AbstractBaseUser.get_email_field_name`.
- .. attribute:: REQUIRED_FIELDS
- A list of the field names that will be prompted for when creating a
- user via the :djadmin:`createsuperuser` management command. The user
- will be prompted to supply a value for each of these fields. It must
- include any field for which :attr:`~django.db.models.Field.blank` is
- ``False`` or undefined and may include additional fields you want
- prompted for when a user is created interactively.
- ``REQUIRED_FIELDS`` has no effect in other parts of Django, like
- creating a user in the admin.
- For example, here is the partial definition for a user model that
- defines two required fields - a date of birth and height::
- class MyUser(AbstractBaseUser):
- ...
- date_of_birth = models.DateField()
- height = models.FloatField()
- ...
- REQUIRED_FIELDS = ['date_of_birth', 'height']
- .. note::
- ``REQUIRED_FIELDS`` must contain all required fields on your user
- model, but should *not* contain the ``USERNAME_FIELD`` or
- ``password`` as these fields will always be prompted for.
- :attr:`REQUIRED_FIELDS` now supports
- :class:`~django.db.models.ForeignKey`\s. Since there is no way to pass
- model instances during the :djadmin:`createsuperuser` prompt, expect the
- user to enter the value of :attr:`~django.db.models.ForeignKey.to_field`
- value (the :attr:`~django.db.models.Field.primary_key` by default) of an
- existing instance.
- .. attribute:: is_active
- A boolean attribute that indicates whether the user is considered
- "active". This attribute is provided as an attribute on
- ``AbstractBaseUser`` defaulting to ``True``. How you choose to
- implement it will depend on the details of your chosen auth backends.
- See the documentation of the :attr:`is_active attribute on the built-in
- user model <django.contrib.auth.models.User.is_active>` for details.
- .. method:: get_full_name()
- A longer formal identifier for the user. A common interpretation
- would be the full name of the user, but it can be any string that
- identifies the user.
- .. method:: get_short_name()
- A short, informal identifier for the user. A common interpretation
- would be the first name of the user, but it can be any string that
- identifies the user in an informal way. It may also return the same
- value as :meth:`django.contrib.auth.models.User.get_full_name()`.
- .. admonition:: Importing ``AbstractBaseUser``
- ``AbstractBaseUser`` and ``BaseUserManager`` are importable from
- ``django.contrib.auth.base_user`` so that they can be imported without
- including ``django.contrib.auth`` in :setting:`INSTALLED_APPS`.
- The following attributes and methods are available on any subclass of
- :class:`~django.contrib.auth.models.AbstractBaseUser`:
- .. class:: models.AbstractBaseUser
- .. method:: get_username()
- Returns the value of the field nominated by ``USERNAME_FIELD``.
- .. method:: clean()
- .. versionadded:: 1.10
- Normalizes the username by calling :meth:`normalize_username`. If you
- override this method, be sure to call ``super()`` to retain the
- normalization.
- .. classmethod:: get_email_field_name()
- .. versionadded:: 1.11
- Returns the name of the email field specified by the
- :attr:`~models.CustomUser.EMAIL_FIELD` attribute. Defaults to
- ``'email'`` if ``EMAIL_FIELD`` isn't specified.
- .. classmethod:: normalize_username(username)
- .. versionadded:: 1.10
- Applies NFKC Unicode normalization to usernames so that visually
- identical characters with different Unicode code points are considered
- identical.
- .. attribute:: models.AbstractBaseUser.is_authenticated
- Read-only attribute which is always ``True`` (as opposed to
- ``AnonymousUser.is_authenticated`` which is always ``False``).
- This is a way to tell if the user has been authenticated. This does not
- imply any permissions and doesn't check if the user is active or has
- a valid session. Even though normally you will check this attribute on
- ``request.user`` to find out whether it has been populated by the
- :class:`~django.contrib.auth.middleware.AuthenticationMiddleware`
- (representing the currently logged-in user), you should know this
- attribute is ``True`` for any :class:`~models.User` instance.
- .. versionchanged:: 1.10
- In older versions, this was a method. Backwards-compatibility
- support for using it as a method will be removed in Django 2.0.
- .. attribute:: models.AbstractBaseUser.is_anonymous
- Read-only attribute which is always ``False``. This is a way of
- differentiating :class:`~models.User` and :class:`~models.AnonymousUser`
- objects. Generally, you should prefer using
- :attr:`~models.User.is_authenticated` to this attribute.
- .. versionchanged:: 1.10
- In older versions, this was a method. Backwards-compatibility
- support for using it as a method will be removed in Django 2.0.
- .. method:: models.AbstractBaseUser.set_password(raw_password)
- Sets the user's password to the given raw string, taking care of the
- password hashing. Doesn't save the
- :class:`~django.contrib.auth.models.AbstractBaseUser` object.
- When the raw_password is ``None``, the password will be set to an
- unusable password, as if
- :meth:`~django.contrib.auth.models.AbstractBaseUser.set_unusable_password()`
- were used.
- .. method:: models.AbstractBaseUser.check_password(raw_password)
- Returns ``True`` if the given raw string is the correct password for
- the user. (This takes care of the password hashing in making the
- comparison.)
- .. method:: models.AbstractBaseUser.set_unusable_password()
- Marks the user as having no password set. This isn't the same as
- having a blank string for a password.
- :meth:`~django.contrib.auth.models.AbstractBaseUser.check_password()` for this user
- will never return ``True``. Doesn't save the
- :class:`~django.contrib.auth.models.AbstractBaseUser` object.
- You may need this if authentication for your application takes place
- against an existing external source such as an LDAP directory.
- .. method:: models.AbstractBaseUser.has_usable_password()
- Returns ``False`` if
- :meth:`~django.contrib.auth.models.AbstractBaseUser.set_unusable_password()` has
- been called for this user.
- .. method:: models.AbstractBaseUser.get_session_auth_hash()
- Returns an HMAC of the password field. Used for
- :ref:`session-invalidation-on-password-change`.
- :class:`~models.AbstractUser` subclasses :class:`~models.AbstractBaseUser`:
- .. class:: models.AbstractUser
- .. method:: clean()
- .. versionadded:: 1.11
- Normalizes the email by calling
- :meth:`.BaseUserManager.normalize_email`. If you override this method,
- be sure to call ``super()`` to retain the normalization.
- You should also define a custom manager for your user model. If your user model
- defines ``username``, ``email``, ``is_staff``, ``is_active``, ``is_superuser``,
- ``last_login``, and ``date_joined`` fields the same as Django's default user,
- you can just install Django's :class:`~django.contrib.auth.models.UserManager`;
- however, if your user model defines different fields, you'll need to define a
- custom manager that extends :class:`~django.contrib.auth.models.BaseUserManager`
- providing two additional methods:
- .. class:: models.CustomUserManager
- .. method:: models.CustomUserManager.create_user(*username_field*, password=None, \**other_fields)
- The prototype of ``create_user()`` should accept the username field,
- plus all required fields as arguments. For example, if your user model
- uses ``email`` as the username field, and has ``date_of_birth`` as a
- required field, then ``create_user`` should be defined as::
- def create_user(self, email, date_of_birth, password=None):
- # create user here
- ...
- .. method:: models.CustomUserManager.create_superuser(*username_field*, password, \**other_fields)
- The prototype of ``create_superuser()`` should accept the username
- field, plus all required fields as arguments. For example, if your user
- model uses ``email`` as the username field, and has ``date_of_birth``
- as a required field, then ``create_superuser`` should be defined as::
- def create_superuser(self, email, date_of_birth, password):
- # create superuser here
- ...
- Unlike ``create_user()``, ``create_superuser()`` *must* require the
- caller to provide a password.
- :class:`~django.contrib.auth.models.BaseUserManager` provides the following
- utility methods:
- .. class:: models.BaseUserManager
- .. classmethod:: models.BaseUserManager.normalize_email(email)
- Normalizes email addresses by lowercasing the domain portion of the
- email address.
- .. method:: models.BaseUserManager.get_by_natural_key(username)
- Retrieves a user instance using the contents of the field
- nominated by ``USERNAME_FIELD``.
- .. method:: models.BaseUserManager.make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')
- Returns a random password with the given length and given string of
- allowed characters. Note that the default value of ``allowed_chars``
- doesn't contain letters that can cause user confusion, including:
- * ``i``, ``l``, ``I``, and ``1`` (lowercase letter i, lowercase
- letter L, uppercase letter i, and the number one)
- * ``o``, ``O``, and ``0`` (lowercase letter o, uppercase letter o,
- and zero)
- Extending Django's default ``User``
- -----------------------------------
- If you're entirely happy with Django's :class:`~django.contrib.auth.models.User`
- model and you just want to add some additional profile information, you could
- simply subclass :class:`django.contrib.auth.models.AbstractUser` and add your
- custom profile fields, although we'd recommend a separate model as described in
- the "Model design considerations" note of :ref:`specifying-custom-user-model`.
- ``AbstractUser`` provides the full implementation of the default
- :class:`~django.contrib.auth.models.User` as an :ref:`abstract model
- <abstract-base-classes>`.
- .. _custom-users-and-the-built-in-auth-forms:
- Custom users and the built-in auth forms
- ----------------------------------------
- Django's built-in :ref:`forms <built-in-auth-forms>` and :ref:`views
- <built-in-auth-views>` make certain assumptions about the user model that they
- are working with.
- The following forms are compatible with any subclass of
- :class:`~django.contrib.auth.models.AbstractBaseUser`:
- * :class:`~django.contrib.auth.forms.AuthenticationForm`: Uses the username
- field specified by :attr:`~models.CustomUser.USERNAME_FIELD`.
- * :class:`~django.contrib.auth.forms.SetPasswordForm`
- * :class:`~django.contrib.auth.forms.PasswordChangeForm`
- * :class:`~django.contrib.auth.forms.AdminPasswordChangeForm`
- The following forms make assumptions about the user model and can be used as-is
- if those assumptions are met:
- * :class:`~django.contrib.auth.forms.PasswordResetForm`: Assumes that the user
- model has a field that stores the user's email address with the name returned
- by :meth:`~models.AbstractBaseUser.get_email_field_name` (``email`` by
- default) that can be used to identify the user and a boolean field named
- ``is_active`` to prevent password resets for inactive users.
- Finally, the following forms are tied to
- :class:`~django.contrib.auth.models.User` and need to be rewritten or extended
- to work with a custom user model:
- * :class:`~django.contrib.auth.forms.UserCreationForm`
- * :class:`~django.contrib.auth.forms.UserChangeForm`
- If your custom user model is a simple subclass of ``AbstractUser``, then you
- can extend these forms in this manner::
- from django.contrib.auth.forms import UserCreationForm
- from myapp.models import CustomUser
- class CustomUserCreationForm(UserCreationForm):
- class Meta(UserCreationForm.Meta):
- model = CustomUser
- fields = UserCreationForm.Meta.fields + ('custom_field',)
- Custom users and :mod:`django.contrib.admin`
- --------------------------------------------
- If you want your custom user model to also work with the admin, your user model
- must define some additional attributes and methods. These methods allow the
- admin to control access of the user to admin content:
- .. class:: models.CustomUser
- .. attribute:: is_staff
- Returns ``True`` if the user is allowed to have access to the admin site.
- .. attribute:: is_active
- Returns ``True`` if the user account is currently active.
- .. method:: has_perm(perm, obj=None):
- Returns ``True`` if the user has the named permission. If ``obj`` is
- provided, the permission needs to be checked against a specific object
- instance.
- .. method:: has_module_perms(app_label):
- Returns ``True`` if the user has permission to access models in
- the given app.
- You will also need to register your custom user model with the admin. If
- your custom user model extends ``django.contrib.auth.models.AbstractUser``,
- you can use Django's existing ``django.contrib.auth.admin.UserAdmin``
- class. However, if your user model extends
- :class:`~django.contrib.auth.models.AbstractBaseUser`, you'll need to define
- a custom ``ModelAdmin`` class. It may be possible to subclass the default
- ``django.contrib.auth.admin.UserAdmin``; however, you'll need to
- override any of the definitions that refer to fields on
- ``django.contrib.auth.models.AbstractUser`` that aren't on your
- custom user class.
- Custom users and permissions
- ----------------------------
- To make it easy to include Django's permission framework into your own user
- class, Django provides :class:`~django.contrib.auth.models.PermissionsMixin`.
- This is an abstract model you can include in the class hierarchy for your user
- model, giving you all the methods and database fields necessary to support
- Django's permission model.
- :class:`~django.contrib.auth.models.PermissionsMixin` provides the following
- methods and attributes:
- .. class:: models.PermissionsMixin
- .. attribute:: models.PermissionsMixin.is_superuser
- Boolean. Designates that this user has all permissions without
- explicitly assigning them.
- .. method:: models.PermissionsMixin.get_group_permissions(obj=None)
- Returns a set of permission strings that the user has, through their
- groups.
- If ``obj`` is passed in, only returns the group permissions for
- this specific object.
- .. method:: models.PermissionsMixin.get_all_permissions(obj=None)
- Returns a set of permission strings that the user has, both through
- group and user permissions.
- If ``obj`` is passed in, only returns the permissions for this
- specific object.
- .. method:: models.PermissionsMixin.has_perm(perm, obj=None)
- Returns ``True`` if the user has the specified permission, where
- ``perm`` is in the format ``"<app label>.<permission codename>"`` (see
- :ref:`permissions <topic-authorization>`). If the user is inactive, this method will
- always return ``False``.
- If ``obj`` is passed in, this method won't check for a permission for
- the model, but for this specific object.
- .. method:: models.PermissionsMixin.has_perms(perm_list, obj=None)
- Returns ``True`` if the user has each of the specified permissions,
- where each perm is in the format
- ``"<app label>.<permission codename>"``. If the user is inactive,
- this method will always return ``False``.
- If ``obj`` is passed in, this method won't check for permissions for
- the model, but for the specific object.
- .. method:: models.PermissionsMixin.has_module_perms(package_name)
- Returns ``True`` if the user has any permissions in the given package
- (the Django app label). If the user is inactive, this method will
- always return ``False``.
- .. admonition:: ``PermissionsMixin`` and ``ModelBackend``
- If you don't include the
- :class:`~django.contrib.auth.models.PermissionsMixin`, you must ensure you
- don't invoke the permissions methods on ``ModelBackend``. ``ModelBackend``
- assumes that certain fields are available on your user model. If your user
- model doesn't provide those fields, you'll receive database errors when
- you check permissions.
- Custom users and proxy models
- -----------------------------
- One limitation of custom user models is that installing a custom user model
- will break any proxy model extending :class:`~django.contrib.auth.models.User`.
- Proxy models must be based on a concrete base class; by defining a custom user
- model, you remove the ability of Django to reliably identify the base class.
- If your project uses proxy models, you must either modify the proxy to extend
- the user model that's in use in your project, or merge your proxy's behavior
- into your :class:`~django.contrib.auth.models.User` subclass.
- A full example
- --------------
- Here is an example of an admin-compliant custom user app. This user model uses
- an email address as the username, and has a required date of birth; it
- provides no permission checking, beyond a simple ``admin`` flag on the user
- account. This model would be compatible with all the built-in auth forms and
- views, except for the user creation forms. This example illustrates how most of
- the components work together, but is not intended to be copied directly into
- projects for production use.
- This code would all live in a ``models.py`` file for a custom
- authentication app::
- from django.db import models
- from django.contrib.auth.models import (
- BaseUserManager, AbstractBaseUser
- )
- class MyUserManager(BaseUserManager):
- def create_user(self, email, date_of_birth, password=None):
- """
- Creates and saves a User with the given email, date of
- birth and password.
- """
- if not email:
- raise ValueError('Users must have an email address')
- user = self.model(
- email=self.normalize_email(email),
- date_of_birth=date_of_birth,
- )
- user.set_password(password)
- user.save(using=self._db)
- return user
- def create_superuser(self, email, date_of_birth, password):
- """
- Creates and saves a superuser with the given email, date of
- birth and password.
- """
- user = self.create_user(
- email,
- password=password,
- date_of_birth=date_of_birth,
- )
- user.is_admin = True
- user.save(using=self._db)
- return user
- class MyUser(AbstractBaseUser):
- email = models.EmailField(
- verbose_name='email address',
- max_length=255,
- unique=True,
- )
- date_of_birth = models.DateField()
- is_active = models.BooleanField(default=True)
- is_admin = models.BooleanField(default=False)
- objects = MyUserManager()
- USERNAME_FIELD = 'email'
- REQUIRED_FIELDS = ['date_of_birth']
- def get_full_name(self):
- # The user is identified by their email address
- return self.email
- def get_short_name(self):
- # The user is identified by their email address
- return self.email
- def __str__(self): # __unicode__ on Python 2
- return self.email
- def has_perm(self, perm, obj=None):
- "Does the user have a specific permission?"
- # Simplest possible answer: Yes, always
- return True
- def has_module_perms(self, app_label):
- "Does the user have permissions to view the app `app_label`?"
- # Simplest possible answer: Yes, always
- return True
- @property
- def is_staff(self):
- "Is the user a member of staff?"
- # Simplest possible answer: All admins are staff
- return self.is_admin
- Then, to register this custom user model with Django's admin, the following
- code would be required in the app's ``admin.py`` file::
- from django import forms
- from django.contrib import admin
- from django.contrib.auth.models import Group
- from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
- from django.contrib.auth.forms import ReadOnlyPasswordHashField
- from customauth.models import MyUser
- class UserCreationForm(forms.ModelForm):
- """A form for creating new users. Includes all the required
- fields, plus a repeated password."""
- password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
- password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
- class Meta:
- model = MyUser
- fields = ('email', 'date_of_birth')
- def clean_password2(self):
- # Check that the two password entries match
- password1 = self.cleaned_data.get("password1")
- password2 = self.cleaned_data.get("password2")
- if password1 and password2 and password1 != password2:
- raise forms.ValidationError("Passwords don't match")
- return password2
- def save(self, commit=True):
- # Save the provided password in hashed format
- user = super(UserCreationForm, self).save(commit=False)
- user.set_password(self.cleaned_data["password1"])
- if commit:
- user.save()
- return user
- class UserChangeForm(forms.ModelForm):
- """A form for updating users. Includes all the fields on
- the user, but replaces the password field with admin's
- password hash display field.
- """
- password = ReadOnlyPasswordHashField()
- class Meta:
- model = MyUser
- fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin')
- def clean_password(self):
- # Regardless of what the user provides, return the initial value.
- # This is done here, rather than on the field, because the
- # field does not have access to the initial value
- return self.initial["password"]
- class UserAdmin(BaseUserAdmin):
- # The forms to add and change user instances
- form = UserChangeForm
- add_form = UserCreationForm
- # The fields to be used in displaying the User model.
- # These override the definitions on the base UserAdmin
- # that reference specific fields on auth.User.
- list_display = ('email', 'date_of_birth', 'is_admin')
- list_filter = ('is_admin',)
- fieldsets = (
- (None, {'fields': ('email', 'password')}),
- ('Personal info', {'fields': ('date_of_birth',)}),
- ('Permissions', {'fields': ('is_admin',)}),
- )
- # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
- # overrides get_fieldsets to use this attribute when creating a user.
- add_fieldsets = (
- (None, {
- 'classes': ('wide',),
- 'fields': ('email', 'date_of_birth', 'password1', 'password2')}
- ),
- )
- search_fields = ('email',)
- ordering = ('email',)
- filter_horizontal = ()
- # Now register the new UserAdmin...
- admin.site.register(MyUser, UserAdmin)
- # ... and, since we're not using Django's built-in permissions,
- # unregister the Group model from admin.
- admin.site.unregister(Group)
- Finally, specify the custom model as the default user model for your project
- using the :setting:`AUTH_USER_MODEL` setting in your ``settings.py``::
- AUTH_USER_MODEL = 'customauth.MyUser'
|