From 8d1b1902488855e56c93f66d5a30b3ec746ff183 Mon Sep 17 00:00:00 2001 From: Preston Holmes Date: Thu, 27 Dec 2012 09:37:57 +0100 Subject: [PATCH] [1.5.x] Fixed #19498 -- refactored auth documentation The auth doc was a single page which had grown unwieldy. This refactor split and grouped the content into sub-topics. Additional corrections and cleanups were made along the way. --- docs/howto/deployment/wsgi/apache-auth.txt | 2 +- docs/index.txt | 2 +- docs/internals/git.txt | 2 +- docs/misc/api-stability.txt | 2 +- docs/ref/authbackends.txt | 33 - docs/ref/contrib/auth.txt | 428 +++- docs/ref/contrib/index.txt | 2 +- docs/ref/django-admin.txt | 4 +- docs/ref/index.txt | 1 - docs/ref/middleware.txt | 4 +- docs/ref/request-response.txt | 2 +- docs/ref/settings.txt | 6 +- docs/ref/signals.txt | 2 +- docs/releases/1.2-beta-1.txt | 4 +- docs/releases/1.2.txt | 4 +- docs/releases/1.3-beta-1.txt | 2 +- docs/releases/1.3.txt | 2 +- docs/topics/auth.txt | 2690 -------------------- docs/topics/auth/customizing.txt | 1068 ++++++++ docs/topics/auth/default.txt | 1077 ++++++++ docs/topics/auth/index.txt | 81 + docs/topics/auth/passwords.txt | 212 ++ docs/topics/db/models.txt | 58 +- docs/topics/index.txt | 2 +- docs/topics/testing/overview.txt | 4 +- 25 files changed, 2914 insertions(+), 2780 deletions(-) delete mode 100644 docs/ref/authbackends.txt delete mode 100644 docs/topics/auth.txt create mode 100644 docs/topics/auth/customizing.txt create mode 100644 docs/topics/auth/default.txt create mode 100644 docs/topics/auth/index.txt create mode 100644 docs/topics/auth/passwords.txt diff --git a/docs/howto/deployment/wsgi/apache-auth.txt b/docs/howto/deployment/wsgi/apache-auth.txt index 5f700f1cb34..220645947d1 100644 --- a/docs/howto/deployment/wsgi/apache-auth.txt +++ b/docs/howto/deployment/wsgi/apache-auth.txt @@ -4,7 +4,7 @@ Authenticating against Django's user database from Apache Since keeping multiple authentication databases in sync is a common problem when dealing with Apache, you can configure Apache to authenticate against Django's -:doc:`authentication system ` directly. This requires Apache +:doc:`authentication system ` directly. This requires Apache version >= 2.2 and mod_wsgi >= 2.0. For example, you could: * Serve static/media files directly from Apache only to authenticated users. diff --git a/docs/index.txt b/docs/index.txt index e8e7eadb23f..971c2ff4797 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -246,7 +246,7 @@ Common Web application tools Django offers multiple tools commonly needed in the development of Web applications: -* :doc:`Authentication ` +* :doc:`Authentication ` * :doc:`Caching ` * :doc:`Logging ` * :doc:`Sending emails ` diff --git a/docs/internals/git.txt b/docs/internals/git.txt index 948f9a1f7e5..2b1a279d899 100644 --- a/docs/internals/git.txt +++ b/docs/internals/git.txt @@ -134,7 +134,7 @@ part of Django itself, and so are no longer separately maintained: of Django since the 0.95 release. * ``multi-auth``: A refactoring of :doc:`Django's bundled - authentication framework ` which added support for + authentication framework ` which added support for :ref:`authentication backends `. This has been part of Django since the 0.95 release. diff --git a/docs/misc/api-stability.txt b/docs/misc/api-stability.txt index a13cb5de69b..70e60065753 100644 --- a/docs/misc/api-stability.txt +++ b/docs/misc/api-stability.txt @@ -38,7 +38,7 @@ In general, everything covered in the documentation -- with the exception of anything in the :doc:`internals area ` is considered stable as of 1.0. This includes these APIs: -- :doc:`Authorization ` +- :doc:`Authorization ` - :doc:`Caching `. diff --git a/docs/ref/authbackends.txt b/docs/ref/authbackends.txt deleted file mode 100644 index 55a536e819e..00000000000 --- a/docs/ref/authbackends.txt +++ /dev/null @@ -1,33 +0,0 @@ -======================= -Authentication backends -======================= - -.. module:: django.contrib.auth.backends - :synopsis: Django's built-in authentication backend classes. - -This document details the authentication backends that come with Django. For -information on how to use them and how to write your own authentication -backends, see the :ref:`Other authentication sources section -` of the :doc:`User authentication guide -`. - - -Available authentication backends -================================= - -The following backends are available in :mod:`django.contrib.auth.backends`: - -.. class:: ModelBackend - - This is the default authentication backend used by Django. It - authenticates using usernames and passwords stored in the - :class:`~django.contrib.auth.models.User` model. - - -.. class:: RemoteUserBackend - - Use this backend to take advantage of external-to-Django-handled - authentication. It authenticates using usernames passed in - :attr:`request.META['REMOTE_USER'] `. See - the :doc:`Authenticating against REMOTE_USER ` - documentation. diff --git a/docs/ref/contrib/auth.txt b/docs/ref/contrib/auth.txt index 619b38e5aca..41f218b0a44 100644 --- a/docs/ref/contrib/auth.txt +++ b/docs/ref/contrib/auth.txt @@ -1,4 +1,430 @@ ``django.contrib.auth`` ======================= -See :doc:`/topics/auth`. +This document provides API reference material for the components of Django's +authentication system. For more details on the usage of these components or +how to customize authentication and authorization see the :doc:`authentication +topic guide `. + +.. currentmodule:: django.contrib.auth + +User +==== + +Fields +------ + +.. class:: models.User + + :class:`~django.contrib.auth.models.User` objects have the following + fields: + + .. attribute:: username + + Required. 30 characters or fewer. Usernames may contain alphanumeric, + ``_``, ``@``, ``+``, ``.`` and ``-`` characters. + + .. attribute:: first_name + + Optional. 30 characters or fewer. + + .. attribute:: last_name + + Optional. 30 characters or fewer. + + .. attribute:: email + + Optional. Email address. + + .. attribute:: password + + Required. A hash of, and metadata about, the password. (Django doesn't + store the raw password.) Raw passwords can be arbitrarily long and can + contain any character. See the :doc:`password documentation + `. + + .. attribute:: groups + + Many-to-many relationship to :class:`~django.contrib.auth.models.Group` + + .. attribute:: user_permissions + + Many-to-many relationship to :class:`~django.contrib.auth.models.Permission` + + .. attribute:: is_staff + + Boolean. Designates whether this user can access the admin site. + + .. attribute:: is_active + + Boolean. Designates whether this user account should be considered + active. We recommend that you set this flag to ``False`` instead of + deleting accounts; that way, if your applications have any foreign keys + to users, the foreign keys won't break. + + This doesn't necessarily control whether or not the user can log in. + Authentication backends aren't required to check for the ``is_active`` + flag, and the default backends do not. If you want to reject a login + based on ``is_active`` being ``False``, it's up to you to check that in + your own login view or a custom authentication backend. However, the + :class:`~django.contrib.auth.forms.AuthenticationForm` used by the + :func:`~django.contrib.auth.views.login` view (which is the default) + *does* perform this check, as do the permission-checking methods such + as :meth:`~django.contrib.auth.models.User.has_perm` and the + authentication in the Django admin. All of those functions/methods will + return ``False`` for inactive users. + + .. attribute:: is_superuser + + Boolean. Designates that this user has all permissions without + explicitly assigning them. + + .. attribute:: last_login + + A datetime of the user's last login. Is set to the current date/time by + default. + + .. attribute:: date_joined + + A datetime designating when the account was created. Is set to the + current date/time by default when the account is created. + +Methods +------- + +.. class:: models.User + + .. method:: get_username() + + Returns the username for the user. Since the User model can be swapped + out, you should use this method instead of referencing the username + attribute directly. + + .. method:: is_anonymous() + + Always returns ``False``. This is a way of differentiating + :class:`~django.contrib.auth.models.User` and + :class:`~django.contrib.auth.models.AnonymousUser` objects. + Generally, you should prefer using + :meth:`~django.contrib.auth.models.User.is_authenticated()` to this + method. + + .. method:: is_authenticated() + + Always returns ``True``. 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 - it only indicates that the user has provided a + valid username and password. + + .. method:: get_full_name() + + Returns the :attr:`~django.contrib.auth.models.User.first_name` plus + the :attr:`~django.contrib.auth.models.User.last_name`, with a space in + between. + + .. method:: 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.User` object. + + .. method:: 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:: 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.User.check_password()` for this user + will never return ``True``. Doesn't save the + :class:`~django.contrib.auth.models.User` object. + + You may need this if authentication for your application takes place + against an existing external source such as an LDAP directory. + + .. method:: has_usable_password() + + Returns ``False`` if + :meth:`~django.contrib.auth.models.User.set_unusable_password()` has + been called for this user. + + .. method:: get_group_permissions(obj=None) + + Returns a set of permission strings that the user has, through his/her + groups. + + If ``obj`` is passed in, only returns the group permissions for + this specific object. + + .. method:: 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:: has_perm(perm, obj=None) + + Returns ``True`` if the user has the specified permission, where perm + is in the format ``"."``. (see + documentation on :ref:`permissions `). 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:: has_perms(perm_list, obj=None) + + Returns ``True`` if the user has each of the specified permissions, + where each perm is in the format + ``"."``. 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:: 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``. + + .. method:: email_user(subject, message, from_email=None) + + Sends an email to the user. If ``from_email`` is ``None``, Django uses + the :setting:`DEFAULT_FROM_EMAIL`. + + .. method:: get_profile() + + .. deprecated:: 1.5 + With the introduction of :ref:`custom User models `, + the use of :setting:`AUTH_PROFILE_MODULE` to define a single profile + model is no longer supported. See the + :doc:`Django 1.5 release notes` for more information. + + Returns a site-specific profile for this user. Raises + ``django.contrib.auth.models.SiteProfileNotAvailable`` if the + current site doesn't allow profiles, or + :exc:`django.core.exceptions.ObjectDoesNotExist` if the user does not + have a profile. + +Manager methods +--------------- + +.. class:: models.UserManager + + The :class:`~django.contrib.auth.models.User` model has a custom manager + that has the following helper methods: + + .. method:: create_user(username, email=None, password=None) + + .. versionchanged:: 1.4 + The ``email`` parameter was made optional. The username + parameter is now checked for emptiness and raises a + :exc:`~exceptions.ValueError` in case of a negative result. + + Creates, saves and returns a :class:`~django.contrib.auth.models.User`. + + The :attr:`~django.contrib.auth.models.User.username` and + :attr:`~django.contrib.auth.models.User.password` are set as given. The + domain portion of :attr:`~django.contrib.auth.models.User.email` is + automatically converted to lowercase, and the returned + :class:`~django.contrib.auth.models.User` object will have + :attr:`~django.contrib.auth.models.User.is_active` set to ``True``. + + If no password is provided, + :meth:`~django.contrib.auth.models.User.set_unusable_password()` will + be called. + + See :ref:`Creating users ` for example usage. + + .. method:: 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`` (uppercase letter o, lowercase letter o, + and zero) + + +Anonymous users +=============== + +.. class:: models.AnonymousUser + + :class:`django.contrib.auth.models.AnonymousUser` is a class that + implements the :class:`django.contrib.auth.models.User` interface, with + these differences: + + * :ref:`id ` is always ``None``. + * :attr:`~django.contrib.auth.models.User.is_staff` and + :attr:`~django.contrib.auth.models.User.is_superuser` are always + ``False``. + * :attr:`~django.contrib.auth.models.User.is_active` is always ``False``. + * :attr:`~django.contrib.auth.models.User.groups` and + :attr:`~django.contrib.auth.models.User.user_permissions` are always + empty. + * :meth:`~django.contrib.auth.models.User.is_anonymous()` returns ``True`` + instead of ``False``. + * :meth:`~django.contrib.auth.models.User.is_authenticated()` returns + ``False`` instead of ``True``. + * :meth:`~django.contrib.auth.models.User.set_password()`, + :meth:`~django.contrib.auth.models.User.check_password()`, + :meth:`~django.db.models.Model.save` and + :meth:`~django.db.models.Model.delete()` raise + :exc:`~exceptions.NotImplementedError`. + +In practice, you probably won't need to use +:class:`~django.contrib.auth.models.AnonymousUser` objects on your own, but +they're used by Web requests, as explained in the next section. + +Permission +========== + +.. class:: models.Permission + +Fields +------ + +:class:`~django.contrib.auth.models.Permission` objects have the following +fields: + +.. attribute:: name + + Required. 50 characters or fewer. Example: ``'Can vote'``. + +.. attribute:: content_type + + Required. A reference to the ``django_content_type`` database table, which + contains a record for each installed Django model. + +.. attribute:: codename + + Required. 100 characters or fewer. Example: ``'can_vote'``. + +Methods +------- + +:class:`~django.contrib.auth.models.Permission` objects have the standard +data-access methods like any other :doc:`Django model `. + +Group +===== + +.. class:: models.Group + +Fields +------ + +:class:`~django.contrib.auth.models.Group` objects have the following fields: + +.. attribute:: name + + Required. 80 characters or fewer. Any characters are permitted. Example: + ``'Awesome Users'``. + +.. attribute:: permissions + + Many-to-many field to :class:`~django.contrib.auth.models.Permission`:: + + group.permissions = [permission_list] + group.permissions.add(permission, permission, ...) + group.permissions.remove(permission, permission, ...) + group.permissions.clear() + +.. _topics-auth-signals: + +Login and logout signals +======================== + +.. module:: django.contrib.auth.signals + +The auth framework uses two :doc:`signals ` that can be used +for notification when a user logs in or out. + +.. function:: django.contrib.auth.signals.user_logged_in + + Sent when a user logs in successfully. + + Arguments sent with this signal: + + ``sender`` + The class of the user that just logged in. + + ``request`` + The current :class:`~django.http.HttpRequest` instance. + + ``user`` + The user instance that just logged in. + +.. function:: django.contrib.auth.signals.user_logged_out + + Sent when the logout method is called. + + ``sender`` + As above: the class of the user that just logged out or ``None`` + if the user was not authenticated. + + ``request`` + The current :class:`~django.http.HttpRequest` instance. + + ``user`` + The user instance that just logged out or ``None`` if the + user was not authenticated. + +.. function:: django.contrib.auth.signals.user_login_failed + +.. versionadded:: 1.5 + + Sent when the user failed to login successfully + + ``sender`` + The name of the module used for authentication. + + ``credentials`` + A dictionary of keyword arguments containing the user credentials that were + passed to :func:`~django.contrib.auth.authenticate()` or your own custom + authentication backend. Credentials matching a set of 'sensitive' patterns, + (including password) will not be sent in the clear as part of the signal. + +.. _authentication-backends-reference: + +Authentication backends +======================= + +.. module:: django.contrib.auth.backends + :synopsis: Django's built-in authentication backend classes. + +This section details the authentication backends that come with Django. For +information on how to use them and how to write your own authentication +backends, see the :ref:`Other authentication sources section +` of the :doc:`User authentication guide +`. + + +Available authentication backends +--------------------------------- + +The following backends are available in :mod:`django.contrib.auth.backends`: + +.. class:: ModelBackend + + This is the default authentication backend used by Django. It + authenticates using usernames and passwords stored in the + :class:`~django.contrib.auth.models.User` model. + + +.. class:: RemoteUserBackend + + Use this backend to take advantage of external-to-Django-handled + authentication. It authenticates using usernames passed in + :attr:`request.META['REMOTE_USER'] `. See + the :doc:`Authenticating against REMOTE_USER ` + documentation. diff --git a/docs/ref/contrib/index.txt b/docs/ref/contrib/index.txt index efe4393f649..3bf5288ee4f 100644 --- a/docs/ref/contrib/index.txt +++ b/docs/ref/contrib/index.txt @@ -56,7 +56,7 @@ auth Django's authentication framework. -See :doc:`/topics/auth`. +See :doc:`/topics/auth/index`. comments ======== diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index 6ab3b1d133e..205f349e8b2 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -1145,7 +1145,7 @@ changepassword .. django-admin:: changepassword This command is only available if Django's :doc:`authentication system -` (``django.contrib.auth``) is installed. +` (``django.contrib.auth``) is installed. Allows changing a user's password. It prompts you to enter twice the password of the user given as parameter. If they both match, the new password will be @@ -1167,7 +1167,7 @@ createsuperuser .. django-admin:: createsuperuser This command is only available if Django's :doc:`authentication system -` (``django.contrib.auth``) is installed. +` (``django.contrib.auth``) is installed. Creates a superuser account (a user who has all permissions). This is useful if you need to create an initial superuser account but did not diff --git a/docs/ref/index.txt b/docs/ref/index.txt index e1959d44a61..fc874a97ebb 100644 --- a/docs/ref/index.txt +++ b/docs/ref/index.txt @@ -5,7 +5,6 @@ API Reference .. toctree:: :maxdepth: 1 - authbackends class-based-views/index clickjacking contrib/index diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt index b542aee6e21..41cff346ff5 100644 --- a/docs/ref/middleware.txt +++ b/docs/ref/middleware.txt @@ -179,8 +179,8 @@ Authentication middleware .. class:: AuthenticationMiddleware Adds the ``user`` attribute, representing the currently-logged-in user, to -every incoming ``HttpRequest`` object. See :doc:`Authentication in Web requests -`. +every incoming ``HttpRequest`` object. See :ref:`Authentication in Web requests +`. CSRF protection middleware -------------------------- diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index c3ba99168db..2775c974d04 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -181,7 +181,7 @@ All attributes should be considered read-only, unless stated otherwise below. ``user`` is only available if your Django installation has the ``AuthenticationMiddleware`` activated. For more, see - :doc:`/topics/auth`. + :doc:`/topics/auth/index`. .. attribute:: HttpRequest.session diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 7cb33a038d0..5815062266e 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -107,8 +107,8 @@ AUTHENTICATION_BACKENDS Default: ``('django.contrib.auth.backends.ModelBackend',)`` A tuple of authentication backend classes (as strings) to use when attempting to -authenticate a user. See the :doc:`authentication backends documentation -` for details. +authenticate a user. See the :ref:`authentication backends documentation +` for details. .. setting:: AUTH_USER_MODEL @@ -2256,7 +2256,7 @@ AUTH_PROFILE_MODULE Default: Not defined The site-specific user profile model used by this site. See -:ref:`auth-profiles`. +:ref:`User profiles `. .. setting:: IGNORABLE_404_ENDS diff --git a/docs/ref/signals.txt b/docs/ref/signals.txt index 2eefb0ca771..0671d80b7c6 100644 --- a/docs/ref/signals.txt +++ b/docs/ref/signals.txt @@ -12,7 +12,7 @@ A list of all the signals that Django sends. The :doc:`comment framework ` sends a :doc:`set of comment-related signals `. - The :doc:`authentication framework ` sends :ref:`signals when + The :doc:`authentication framework ` sends :ref:`signals when a user is logged in / out `. Model signals diff --git a/docs/releases/1.2-beta-1.txt b/docs/releases/1.2-beta-1.txt index 99cd2749578..3549767379b 100644 --- a/docs/releases/1.2-beta-1.txt +++ b/docs/releases/1.2-beta-1.txt @@ -91,7 +91,7 @@ added in Django 1.2 alpha but not documented with the alpha release. The default authentication backends shipped with Django do not currently make use of this, but third-party authentication backends -are free to do so. See the :doc:`authentication docs ` +are free to do so. See the :doc:`authentication docs ` for more information. @@ -104,7 +104,7 @@ class will check the backend for permissions, just as the normal ``User`` does. This is intended to help centralize permission handling; apps can always delegate the question of whether something is allowed or not to the authorization/authentication system. See the -:doc:`authentication docs ` for more details. +:doc:`authentication docs ` for more details. ``select_related()`` improvements diff --git a/docs/releases/1.2.txt b/docs/releases/1.2.txt index 26a94055956..68cec915877 100644 --- a/docs/releases/1.2.txt +++ b/docs/releases/1.2.txt @@ -165,7 +165,7 @@ A foundation for specifying permissions at the per-object level has been added. Although there is no implementation of this in core, a custom authentication backend can provide this implementation and it will be used by :class:`django.contrib.auth.models.User`. See the :doc:`authentication docs -` for more information. +` for more information. Permissions for anonymous users ------------------------------- @@ -175,7 +175,7 @@ If you provide a custom auth backend with ``supports_anonymous_user`` set to User already did. This is useful for centralizing permission handling - apps can always delegate the question of whether something is allowed or not to the authorization/authentication backend. See the :doc:`authentication -docs ` for more details. +docs ` for more details. Relaxed requirements for usernames ---------------------------------- diff --git a/docs/releases/1.3-beta-1.txt b/docs/releases/1.3-beta-1.txt index 02c038f4593..2729c7f2bab 100644 --- a/docs/releases/1.3-beta-1.txt +++ b/docs/releases/1.3-beta-1.txt @@ -61,7 +61,7 @@ Permissions for inactive users If you provide a custom auth backend with ``supports_inactive_user`` set to ``True``, an inactive user model will check the backend for permissions. This is useful for further centralizing the permission handling. See the -:doc:`authentication docs ` for more details. +:doc:`authentication docs ` for more details. Backwards-incompatible changes in 1.3 alpha 2 ============================================= diff --git a/docs/releases/1.3.txt b/docs/releases/1.3.txt index c507f1bed6f..d6ef11d1131 100644 --- a/docs/releases/1.3.txt +++ b/docs/releases/1.3.txt @@ -254,7 +254,7 @@ Permissions for inactive users If you provide a custom auth backend with ``supports_inactive_user`` set to ``True``, an inactive ``User`` instance will check the backend for permissions. This is useful for further centralizing the -permission handling. See the :doc:`authentication docs ` +permission handling. See the :doc:`authentication docs ` for more details. GeoDjango diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt deleted file mode 100644 index 8bc2ced1a77..00000000000 --- a/docs/topics/auth.txt +++ /dev/null @@ -1,2690 +0,0 @@ -============================= -User authentication in Django -============================= - -.. module:: django.contrib.auth - :synopsis: Django's authentication framework. - -Django comes with a user authentication system. It handles user accounts, -groups, permissions and cookie-based user sessions. This document explains how -things work. - -Overview -======== - -The auth system consists of: - -* Users -* Permissions: Binary (yes/no) flags designating whether a user may perform - a certain task. -* Groups: A generic way of applying labels and permissions to more than one - user. - -Installation -============ - -Authentication support is bundled as a Django application in -``django.contrib.auth``. To install it, do the following: - -1. Put ``'django.contrib.auth'`` and ``'django.contrib.contenttypes'`` in - your :setting:`INSTALLED_APPS` setting. - (The :class:`~django.contrib.auth.models.Permission` model in - :mod:`django.contrib.auth` depends on :mod:`django.contrib.contenttypes`.) -2. Run the command ``manage.py syncdb``. - -Note that the default :file:`settings.py` file created by -:djadmin:`django-admin.py startproject ` includes -``'django.contrib.auth'`` and ``'django.contrib.contenttypes'`` in -:setting:`INSTALLED_APPS` for convenience. If your :setting:`INSTALLED_APPS` -already contains these apps, feel free to run :djadmin:`manage.py syncdb -` again; you can run that command as many times as you'd like, and each -time it'll only install what's needed. - -The :djadmin:`syncdb` command creates the necessary database tables, creates -permission objects for all installed apps that need 'em, and prompts you to -create a superuser account the first time you run it. - -Once you've taken those steps, that's it. - -Users -===== - -.. class:: models.User - -API reference -------------- - -Fields -~~~~~~ - -.. class:: models.User - - :class:`~django.contrib.auth.models.User` objects have the following - fields: - - .. attribute:: models.User.username - - Required. 30 characters or fewer. Usernames may contain alphanumeric, - ``_``, ``@``, ``+``, ``.`` and ``-`` characters. - - .. attribute:: models.User.first_name - - Optional. 30 characters or fewer. - - .. attribute:: models.User.last_name - - Optional. 30 characters or fewer. - - .. attribute:: models.User.email - - Optional. Email address. - - .. attribute:: models.User.password - - Required. A hash of, and metadata about, the password. (Django doesn't - store the raw password.) Raw passwords can be arbitrarily long and can - contain any character. See the "Passwords" section below. - - .. attribute:: models.User.is_staff - - Boolean. Designates whether this user can access the admin site. - - .. attribute:: models.User.is_active - - Boolean. Designates whether this user account should be considered - active. We recommend that you set this flag to ``False`` instead of - deleting accounts; that way, if your applications have any foreign keys - to users, the foreign keys won't break. - - This doesn't necessarily control whether or not the user can log in. - Authentication backends aren't required to check for the ``is_active`` - flag, and the default backends do not. If you want to reject a login - based on ``is_active`` being ``False``, it's up to you to check that in - your own login view or a custom authentication backend. However, the - :class:`~django.contrib.auth.forms.AuthenticationForm` used by the - :func:`~django.contrib.auth.views.login` view (which is the default) - *does* perform this check, as do the permission-checking methods such - as :meth:`~models.User.has_perm` and the authentication in the Django - admin. All of those functions/methods will return ``False`` for - inactive users. - - .. attribute:: models.User.is_superuser - - Boolean. Designates that this user has all permissions without - explicitly assigning them. - - .. attribute:: models.User.last_login - - A datetime of the user's last login. Is set to the current date/time by - default. - - .. attribute:: models.User.date_joined - - A datetime designating when the account was created. Is set to the - current date/time by default when the account is created. - -Methods -~~~~~~~ - -.. class:: models.User - - :class:`~django.contrib.auth.models.User` objects have two many-to-many - fields: ``groups`` and ``user_permissions``. - :class:`~django.contrib.auth.models.User` objects can access their related - objects in the same way as any other :doc:`Django model - `: - - .. code-block:: python - - myuser.groups = [group_list] - myuser.groups.add(group, group, ...) - myuser.groups.remove(group, group, ...) - myuser.groups.clear() - myuser.user_permissions = [permission_list] - myuser.user_permissions.add(permission, permission, ...) - myuser.user_permissions.remove(permission, permission, ...) - myuser.user_permissions.clear() - - In addition to those automatic API methods, - :class:`~django.contrib.auth.models.User` objects have the following custom - methods: - - .. method:: models.User.get_username() - - Returns the username for the user. Since the User model can be swapped - out, you should use this method instead of referencing the username - attribute directly. - - .. method:: models.User.is_anonymous() - - Always returns ``False``. This is a way of differentiating - :class:`~django.contrib.auth.models.User` and - :class:`~django.contrib.auth.models.AnonymousUser` objects. - Generally, you should prefer using - :meth:`~django.contrib.auth.models.User.is_authenticated()` to this - method. - - .. method:: models.User.is_authenticated() - - Always returns ``True``. 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 - it only indicates that the user has provided a - valid username and password. - - .. method:: models.User.get_full_name() - - Returns the :attr:`~django.contrib.auth.models.User.first_name` plus - the :attr:`~django.contrib.auth.models.User.last_name`, with a space in - between. - - .. method:: models.User.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.User` object. - - .. method:: models.User.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.User.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.User.check_password()` for this user - will never return ``True``. Doesn't save the - :class:`~django.contrib.auth.models.User` object. - - You may need this if authentication for your application takes place - against an existing external source such as an LDAP directory. - - .. method:: models.User.has_usable_password() - - Returns ``False`` if - :meth:`~django.contrib.auth.models.User.set_unusable_password()` has - been called for this user. - - .. method:: models.User.get_group_permissions(obj=None) - - Returns a set of permission strings that the user has, through his/her - groups. - - If ``obj`` is passed in, only returns the group permissions for - this specific object. - - .. method:: models.User.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.User.has_perm(perm, obj=None) - - Returns ``True`` if the user has the specified permission, where perm is - in the format ``"."``. (see - `permissions`_ section below). 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.User.has_perms(perm_list, obj=None) - - Returns ``True`` if the user has each of the specified permissions, - where each perm is in the format - ``"."``. 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.User.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``. - - .. method:: models.User.email_user(subject, message, from_email=None) - - Sends an email to the user. If - :attr:`~django.contrib.auth.models.User.from_email` is ``None``, Django - uses the :setting:`DEFAULT_FROM_EMAIL`. - - .. method:: models.User.get_profile() - - .. deprecated:: 1.5 - With the introduction of :ref:`custom User models `, - the use of :setting:`AUTH_PROFILE_MODULE` to define a single profile - model is no longer supported. See the - :doc:`Django 1.5 release notes` for more information. - - Returns a site-specific profile for this user. Raises - :exc:`django.contrib.auth.models.SiteProfileNotAvailable` if the - current site doesn't allow profiles, or - :exc:`django.core.exceptions.ObjectDoesNotExist` if the user does not - have a profile. For information on how to define a site-specific user - profile, see the section on `storing additional user information`_ below. - -.. _storing additional user information: #storing-additional-information-about-users - -Manager functions -~~~~~~~~~~~~~~~~~ - -.. class:: models.UserManager - - The :class:`~django.contrib.auth.models.User` model has a custom manager - that has the following helper functions: - - .. method:: models.UserManager.create_user(username, email=None, password=None) - - .. versionchanged:: 1.4 - The ``email`` parameter was made optional. The username - parameter is now checked for emptiness and raises a - :exc:`~exceptions.ValueError` in case of a negative result. - - Creates, saves and returns a :class:`~django.contrib.auth.models.User`. - - The :attr:`~django.contrib.auth.models.User.username` and - :attr:`~django.contrib.auth.models.User.password` are set as given. The - domain portion of :attr:`~django.contrib.auth.models.User.email` is - automatically converted to lowercase, and the returned - :class:`~django.contrib.auth.models.User` object will have - :attr:`~models.User.is_active` set to ``True``. - - If no password is provided, - :meth:`~django.contrib.auth.models.User.set_unusable_password()` will - be called. - - See `Creating users`_ for example usage. - - .. method:: models.UserManager.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`` (uppercase letter o, lowercase letter o, - and zero) - -Basic usage ------------ - -.. _topics-auth-creating-users: - -Creating users -~~~~~~~~~~~~~~ - -The most basic way to create users is to use the -:meth:`~django.contrib.auth.models.UserManager.create_user` helper function -that comes with Django:: - - >>> from django.contrib.auth.models import User - >>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword') - - # At this point, user is a User object that has already been saved - # to the database. You can continue to change its attributes - # if you want to change other fields. - >>> user.is_staff = True - >>> user.save() - -You can also create users using the Django admin site. Assuming you've enabled -the admin site and hooked it to the URL ``/admin/``, the "Add user" page is at -``/admin/auth/user/add/``. You should also see a link to "Users" in the "Auth" -section of the main admin index page. The "Add user" admin page is different -than standard admin pages in that it requires you to choose a username and -password before allowing you to edit the rest of the user's fields. - -Also note: if you want your own user account to be able to create users using -the Django admin site, you'll need to give yourself permission to add users -*and* change users (i.e., the "Add user" and "Change user" permissions). If -your account has permission to add users but not to change them, you won't be -able to add users. Why? Because if you have permission to add users, you have -the power to create superusers, which can then, in turn, change other users. So -Django requires add *and* change permissions as a slight security measure. - -Changing passwords -~~~~~~~~~~~~~~~~~~ - -:djadmin:`manage.py changepassword *username* ` offers a method -of changing a User's password from the command line. It prompts you to -change the password of a given user which you must enter twice. If -they both match, the new password will be changed immediately. If you -do not supply a user, the command will attempt to change the password -whose username matches the current user. - -You can also change a password programmatically, using -:meth:`~django.contrib.auth.models.User.set_password()`: - -.. code-block:: python - - >>> from django.contrib.auth.models import User - >>> u = User.objects.get(username__exact='john') - >>> u.set_password('new password') - >>> u.save() - -Don't set the :attr:`~django.contrib.auth.models.User.password` attribute -directly unless you know what you're doing. This is explained in the next -section. - -.. _auth_password_storage: - -How Django stores passwords ---------------------------- - -.. versionadded:: 1.4 - Django 1.4 introduces a new flexible password storage system and uses - PBKDF2 by default. Previous versions of Django used SHA1, and other - algorithms couldn't be chosen. - -The :attr:`~django.contrib.auth.models.User.password` attribute of a -:class:`~django.contrib.auth.models.User` object is a string in this format:: - - algorithm$hash - -That's a storage algorithm, and hash, separated by the dollar-sign -character. The algorithm is one of a number of one way hashing or password -storage algorithms Django can use; see below. The hash is the result of the one- -way function. - -By default, Django uses the PBKDF2_ algorithm with a SHA256 hash, a -password stretching mechanism recommended by NIST_. This should be -sufficient for most users: it's quite secure, requiring massive -amounts of computing time to break. - -However, depending on your requirements, you may choose a different -algorithm, or even use a custom algorithm to match your specific -security situation. Again, most users shouldn't need to do this -- if -you're not sure, you probably don't. If you do, please read on: - -Django chooses the an algorithm by consulting the :setting:`PASSWORD_HASHERS` -setting. This is a list of hashing algorithm classes that this Django -installation supports. The first entry in this list (that is, -``settings.PASSWORD_HASHERS[0]``) will be used to store passwords, and all the -other entries are valid hashers that can be used to check existing passwords. -This means that if you want to use a different algorithm, you'll need to modify -:setting:`PASSWORD_HASHERS` to list your preferred algorithm first in the list. - -The default for :setting:`PASSWORD_HASHERS` is:: - - PASSWORD_HASHERS = ( - 'django.contrib.auth.hashers.PBKDF2PasswordHasher', - 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', - 'django.contrib.auth.hashers.BCryptPasswordHasher', - 'django.contrib.auth.hashers.SHA1PasswordHasher', - 'django.contrib.auth.hashers.MD5PasswordHasher', - 'django.contrib.auth.hashers.CryptPasswordHasher', - ) - -This means that Django will use PBKDF2_ to store all passwords, but will support -checking passwords stored with PBKDF2SHA1, bcrypt_, SHA1_, etc. The next few -sections describe a couple of common ways advanced users may want to modify this -setting. - -.. _bcrypt_usage: - -Using bcrypt with Django -~~~~~~~~~~~~~~~~~~~~~~~~ - -Bcrypt_ is a popular password storage algorithm that's specifically designed -for long-term password storage. It's not the default used by Django since it -requires the use of third-party libraries, but since many people may want to -use it Django supports bcrypt with minimal effort. - -To use Bcrypt as your default storage algorithm, do the following: - -1. Install the `py-bcrypt`_ library (probably by running ``sudo pip install - py-bcrypt``, or downloading the library and installing it with ``python - setup.py install``). - -2. Modify :setting:`PASSWORD_HASHERS` to list ``BCryptPasswordHasher`` - first. That is, in your settings file, you'd put:: - - PASSWORD_HASHERS = ( - 'django.contrib.auth.hashers.BCryptPasswordHasher', - 'django.contrib.auth.hashers.PBKDF2PasswordHasher', - 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', - 'django.contrib.auth.hashers.SHA1PasswordHasher', - 'django.contrib.auth.hashers.MD5PasswordHasher', - 'django.contrib.auth.hashers.CryptPasswordHasher', - ) - - (You need to keep the other entries in this list, or else Django won't - be able to upgrade passwords; see below). - -That's it -- now your Django install will use Bcrypt as the default storage -algorithm. - -.. admonition:: Other bcrypt implementations - - There are several other implementations that allow bcrypt to be - used with Django. Django's bcrypt support is NOT directly - compatible with these. To upgrade, you will need to modify the - hashes in your database to be in the form `bcrypt$(raw bcrypt - output)`. For example: - `bcrypt$$2a$12$NT0I31Sa7ihGEWpka9ASYrEFkhuTNeBQ2xfZskIiiJeyFXhRgS.Sy`. - -Increasing the work factor -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The PBKDF2 and bcrypt algorithms use a number of iterations or rounds of -hashing. This deliberately slows down attackers, making attacks against hashed -passwords harder. However, as computing power increases, the number of -iterations needs to be increased. We've chosen a reasonable default (and will -increase it with each release of Django), but you may wish to tune it up or -down, depending on your security needs and available processing power. To do so, -you'll subclass the appropriate algorithm and override the ``iterations`` -parameters. For example, to increase the number of iterations used by the -default PBKDF2 algorithm: - -1. Create a subclass of ``django.contrib.auth.hashers.PBKDF2PasswordHasher``:: - - from django.contrib.auth.hashers import PBKDF2PasswordHasher - - class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher): - """ - A subclass of PBKDF2PasswordHasher that uses 100 times more iterations. - """ - iterations = PBKDF2PasswordHasher.iterations * 100 - - Save this somewhere in your project. For example, you might put this in - a file like ``myproject/hashers.py``. - -2. Add your new hasher as the first entry in :setting:`PASSWORD_HASHERS`:: - - PASSWORD_HASHERS = ( - 'myproject.hashers.MyPBKDF2PasswordHasher', - 'django.contrib.auth.hashers.PBKDF2PasswordHasher', - 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', - 'django.contrib.auth.hashers.BCryptPasswordHasher', - 'django.contrib.auth.hashers.SHA1PasswordHasher', - 'django.contrib.auth.hashers.MD5PasswordHasher', - 'django.contrib.auth.hashers.CryptPasswordHasher', - ) - - -That's it -- now your Django install will use more iterations when it -stores passwords using PBKDF2. - -Password upgrading -~~~~~~~~~~~~~~~~~~ - -When users log in, if their passwords are stored with anything other than -the preferred algorithm, Django will automatically upgrade the algorithm -to the preferred one. This means that old installs of Django will get -automatically more secure as users log in, and it also means that you -can switch to new (and better) storage algorithms as they get invented. - -However, Django can only upgrade passwords that use algorithms mentioned in -:setting:`PASSWORD_HASHERS`, so as you upgrade to new systems you should make -sure never to *remove* entries from this list. If you do, users using un- -mentioned algorithms won't be able to upgrade. - -.. _sha1: http://en.wikipedia.org/wiki/SHA1 -.. _pbkdf2: http://en.wikipedia.org/wiki/PBKDF2 -.. _nist: http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf -.. _bcrypt: http://en.wikipedia.org/wiki/Bcrypt -.. _py-bcrypt: http://pypi.python.org/pypi/py-bcrypt/ - -Anonymous users ---------------- - -.. class:: models.AnonymousUser - - :class:`django.contrib.auth.models.AnonymousUser` is a class that - implements the :class:`django.contrib.auth.models.User` interface, with - these differences: - - * :attr:`~django.contrib.auth.models.User.id` is always ``None``. - * :attr:`~django.contrib.auth.models.User.is_staff` and - :attr:`~django.contrib.auth.models.User.is_superuser` are always - ``False``. - * :attr:`~django.contrib.auth.models.User.is_active` is always ``False``. - * :attr:`~django.contrib.auth.models.User.groups` and - :attr:`~django.contrib.auth.models.User.user_permissions` are always - empty. - * :meth:`~django.contrib.auth.models.User.is_anonymous()` returns ``True`` - instead of ``False``. - * :meth:`~django.contrib.auth.models.User.is_authenticated()` returns - ``False`` instead of ``True``. - * :meth:`~django.contrib.auth.models.User.set_password()`, - :meth:`~django.contrib.auth.models.User.check_password()`, - :meth:`~django.contrib.auth.models.User.save()`, - :meth:`~django.contrib.auth.models.User.delete()`, - :meth:`~django.contrib.auth.models.User.set_groups()` and - :meth:`~django.contrib.auth.models.User.set_permissions()` raise - :exc:`~exceptions.NotImplementedError`. - -In practice, you probably won't need to use -:class:`~django.contrib.auth.models.AnonymousUser` objects on your own, but -they're used by Web requests, as explained in the next section. - -.. _topics-auth-creating-superusers: - -Creating superusers -------------------- - -:djadmin:`manage.py syncdb ` prompts you to create a superuser the -first time you run it after adding ``'django.contrib.auth'`` to your -:setting:`INSTALLED_APPS`. If you need to create a superuser at a later date, -you can use a command line utility:: - - manage.py createsuperuser --username=joe --email=joe@example.com - -You will be prompted for a password. After you enter one, the user will be -created immediately. If you leave off the :djadminopt:`--username` or the -:djadminopt:`--email` options, it will prompt you for those values. - -If you're using an older release of Django, the old way of creating a superuser -on the command line still works:: - - python /path/to/django/contrib/auth/create_superuser.py - -...where :file:`/path/to` is the path to the Django codebase on your -filesystem. The ``manage.py`` command is preferred because it figures out the -correct path and environment for you. - -.. _auth-profiles: - -Storing additional information about users ------------------------------------------- - -.. deprecated:: 1.5 - With the introduction of :ref:`custom User models `, - the use of :setting:`AUTH_PROFILE_MODULE` to define a single profile - model is no longer supported. See the - :doc:`Django 1.5 release notes` for more information. - -If you'd like to store additional information related to your users, Django -provides a method to specify a site-specific related model -- termed a "user -profile" -- for this purpose. - -To make use of this feature, define a model with fields for the -additional information you'd like to store, or additional methods -you'd like to have available, and also add a -:class:`~django.db.models.Field.OneToOneField` named ``user`` from your model -to the :class:`~django.contrib.auth.models.User` model. This will ensure only -one instance of your model can be created for each -:class:`~django.contrib.auth.models.User`. For example:: - - from django.contrib.auth.models import User - - class UserProfile(models.Model): - # This field is required. - user = models.OneToOneField(User) - - # Other fields here - accepted_eula = models.BooleanField() - favorite_animal = models.CharField(max_length=20, default="Dragons.") - - -To indicate that this model is the user profile model for a given site, fill in -the setting :setting:`AUTH_PROFILE_MODULE` with a string consisting of the -following items, separated by a dot: - -1. The name of the application (case sensitive) in which the user - profile model is defined (in other words, the - name which was passed to :djadmin:`manage.py startapp ` to create - the application). - -2. The name of the model (not case sensitive) class. - -For example, if the profile model was a class named ``UserProfile`` and was -defined inside an application named ``accounts``, the appropriate setting would -be:: - - AUTH_PROFILE_MODULE = 'accounts.UserProfile' - -When a user profile model has been defined and specified in this manner, each -:class:`~django.contrib.auth.models.User` object will have a method -- -:class:`~django.contrib.auth.models.User.get_profile()` -- which returns the -instance of the user profile model associated with that -:class:`~django.contrib.auth.models.User`. - -The method :class:`~django.contrib.auth.models.User.get_profile()` -does not create a profile if one does not exist. You need to register a handler -for the User model's :attr:`django.db.models.signals.post_save` signal and, in -the handler, if ``created`` is ``True``, create the associated user profile:: - - # in models.py - - from django.contrib.auth.models import User - from django.db.models.signals import post_save - - # definition of UserProfile from above - # ... - - def create_user_profile(sender, instance, created, **kwargs): - if created: - UserProfile.objects.create(user=instance) - - post_save.connect(create_user_profile, sender=User) - -.. seealso:: :doc:`/topics/signals` for more information on Django's signal - dispatcher. - -Adding UserProfile fields to the admin --------------------------------------- - -To add the UserProfile 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 - from django.contrib.auth.models import User - - from my_user_profile_app.models import UserProfile - - # Define an inline admin descriptor for UserProfile model - # which acts a bit like a singleton - class UserProfileInline(admin.StackedInline): - model = UserProfile - can_delete = False - verbose_name_plural = 'profile' - - # Define a new User admin - class UserAdmin(UserAdmin): - inlines = (UserProfileInline, ) - - # Re-register UserAdmin - admin.site.unregister(User) - admin.site.register(User, UserAdmin) - -Authentication in Web requests -============================== - -Until now, this document has dealt with the low-level APIs for manipulating -authentication-related objects. On a higher level, Django can hook this -authentication framework into its system of -:class:`request objects `. - -First, install the -:class:`~django.contrib.sessions.middleware.SessionMiddleware` and -:class:`~django.contrib.auth.middleware.AuthenticationMiddleware` -middlewares by adding them to your :setting:`MIDDLEWARE_CLASSES` setting. See -the :doc:`session documentation ` for more information. - -Once you have those middlewares installed, you'll be able to access -:attr:`request.user ` in views. -:attr:`request.user ` will give you a -:class:`~django.contrib.auth.models.User` object representing the currently -logged-in user. If a user isn't currently logged in, -:attr:`request.user ` will be set to an instance -of :class:`~django.contrib.auth.models.AnonymousUser` (see the previous -section). You can tell them apart with -:meth:`~django.contrib.auth.models.User.is_authenticated()`, like so:: - - if request.user.is_authenticated(): - # Do something for authenticated users. - else: - # Do something for anonymous users. - -.. _how-to-log-a-user-in: - -How to log a user in --------------------- - -Django provides two functions in :mod:`django.contrib.auth`: -:func:`~django.contrib.auth.authenticate()` and -:func:`~django.contrib.auth.login()`. - -.. function:: authenticate() - - To authenticate a given username and password, use - :func:`~django.contrib.auth.authenticate()`. It takes two keyword - arguments, ``username`` and ``password``, and it returns a - :class:`~django.contrib.auth.models.User` object if the password is valid - for the given username. If the password is invalid, - :func:`~django.contrib.auth.authenticate()` returns ``None``. Example:: - - from django.contrib.auth import authenticate - user = authenticate(username='john', password='secret') - if user is not None: - if user.is_active: - print("You provided a correct username and password!") - else: - print("Your account has been disabled!") - else: - print("Your username and password were incorrect.") - -.. function:: login() - - To log a user in, in a view, use :func:`~django.contrib.auth.login()`. It - takes an :class:`~django.http.HttpRequest` object and a - :class:`~django.contrib.auth.models.User` object. - :func:`~django.contrib.auth.login()` saves the user's ID in the session, - using Django's session framework, so, as mentioned above, you'll need to - make sure to have the session middleware installed. - - Note that data set during the anonymous session is retained when the user - logs in. - - This example shows how you might use both - :func:`~django.contrib.auth.authenticate()` and - :func:`~django.contrib.auth.login()`:: - - from django.contrib.auth import authenticate, login - - def my_view(request): - username = request.POST['username'] - password = request.POST['password'] - user = authenticate(username=username, password=password) - if user is not None: - if user.is_active: - login(request, user) - # Redirect to a success page. - else: - # Return a 'disabled account' error message - else: - # Return an 'invalid login' error message. - -.. admonition:: Calling ``authenticate()`` first - - When you're manually logging a user in, you *must* call - :func:`~django.contrib.auth.authenticate()` before you call - :func:`~django.contrib.auth.login()`. - :func:`~django.contrib.auth.authenticate()` - sets an attribute on the :class:`~django.contrib.auth.models.User` noting - which authentication backend successfully authenticated that user (see the - `backends documentation`_ for details), and this information is needed - later during the login process. - -.. _backends documentation: #other-authentication-sources - -Manually managing a user's password ------------------------------------ - -.. currentmodule:: django.contrib.auth.hashers - -.. versionadded:: 1.4 - The :mod:`django.contrib.auth.hashers` module provides a set of functions - to create and validate hashed password. You can use them independently - from the ``User`` model. - -.. function:: check_password(password, encoded) - - .. versionadded:: 1.4 - - If you'd like to manually authenticate a user by comparing a plain-text - password to the hashed password in the database, use the convenience - function :func:`django.contrib.auth.hashers.check_password`. It takes two - arguments: the plain-text password to check, and the full value of a - user's ``password`` field in the database to check against, and returns - ``True`` if they match, ``False`` otherwise. - -.. function:: make_password(password[, salt, hashers]) - - .. versionadded:: 1.4 - - Creates a hashed password in the format used by this application. It takes - one mandatory argument: the password in plain-text. Optionally, you can - provide a salt and a hashing algorithm to use, if you don't want to use the - defaults (first entry of ``PASSWORD_HASHERS`` setting). - Currently supported algorithms are: ``'pbkdf2_sha256'``, ``'pbkdf2_sha1'``, - ``'bcrypt'`` (see :ref:`bcrypt_usage`), ``'sha1'``, ``'md5'``, - ``'unsalted_md5'`` (only for backward compatibility) and ``'crypt'`` - if you have the ``crypt`` library installed. If the password argument is - ``None``, an unusable password is returned (a one that will be never - accepted by :func:`django.contrib.auth.hashers.check_password`). - -.. function:: is_password_usable(encoded_password) - - .. versionadded:: 1.4 - - Checks if the given string is a hashed password that has a chance - of being verified against :func:`django.contrib.auth.hashers.check_password`. - - -How to log a user out ---------------------- - -.. currentmodule:: django.contrib.auth - -.. function:: logout() - - To log out a user who has been logged in via - :func:`django.contrib.auth.login()`, use - :func:`django.contrib.auth.logout()` within your view. It takes an - :class:`~django.http.HttpRequest` object and has no return value. - Example:: - - from django.contrib.auth import logout - - def logout_view(request): - logout(request) - # Redirect to a success page. - - Note that :func:`~django.contrib.auth.logout()` doesn't throw any errors if - the user wasn't logged in. - - When you call :func:`~django.contrib.auth.logout()`, the session data for - the current request is completely cleaned out. All existing data is - removed. This is to prevent another person from using the same Web browser - to log in and have access to the previous user's session data. If you want - to put anything into the session that will be available to the user - immediately after logging out, do that *after* calling - :func:`django.contrib.auth.logout()`. - -.. _topics-auth-signals: - -Login and logout signals ------------------------- - -The auth framework uses two :doc:`signals ` that can be used -for notification when a user logs in or out. - -.. data:: django.contrib.auth.signals.user_logged_in - :module: - -Sent when a user logs in successfully. - -Arguments sent with this signal: - -``sender`` - The class of the user that just logged in. - -``request`` - The current :class:`~django.http.HttpRequest` instance. - -``user`` - The user instance that just logged in. - -.. data:: django.contrib.auth.signals.user_logged_out - :module: - -Sent when the logout method is called. - -``sender`` - As above: the class of the user that just logged out or ``None`` - if the user was not authenticated. - -``request`` - The current :class:`~django.http.HttpRequest` instance. - -``user`` - The user instance that just logged out or ``None`` if the - user was not authenticated. - -.. data:: django.contrib.auth.signals.user_login_failed - :module: -.. versionadded:: 1.5 - -Sent when the user failed to login successfully - -``sender`` - The name of the module used for authentication. - -``credentials`` - A dictonary of keyword arguments containing the user credentials that were - passed to :func:`~django.contrib.auth.authenticate()` or your own custom - authentication backend. Credentials matching a set of 'sensitive' patterns, - (including password) will not be sent in the clear as part of the signal. - -Limiting access to logged-in users ----------------------------------- - -The raw way -~~~~~~~~~~~ - -The simple, raw way to limit access to pages is to check -:meth:`request.user.is_authenticated() -` and either redirect to a -login page:: - - from django.http import HttpResponseRedirect - - def my_view(request): - if not request.user.is_authenticated(): - return HttpResponseRedirect('/login/?next=%s' % request.path) - # ... - -...or display an error message:: - - def my_view(request): - if not request.user.is_authenticated(): - return render_to_response('myapp/login_error.html') - # ... - -The login_required decorator -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. function:: decorators.login_required([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None]) - - As a shortcut, you can use the convenient - :func:`~django.contrib.auth.decorators.login_required` decorator:: - - from django.contrib.auth.decorators import login_required - - @login_required - def my_view(request): - ... - - :func:`~django.contrib.auth.decorators.login_required` does the following: - - * If the user isn't logged in, redirect to - :setting:`settings.LOGIN_URL `, passing the current absolute - path in the query string. Example: ``/accounts/login/?next=/polls/3/``. - - * If the user is logged in, execute the view normally. The view code is - free to assume the user is logged in. - - By default, the path that the user should be redirected to upon - successful authentication is stored in a query string parameter called - ``"next"``. If you would prefer to use a different name for this parameter, - :func:`~django.contrib.auth.decorators.login_required` takes an - optional ``redirect_field_name`` parameter:: - - from django.contrib.auth.decorators import login_required - - @login_required(redirect_field_name='my_redirect_field') - def my_view(request): - ... - - Note that if you provide a value to ``redirect_field_name``, you will most - likely need to customize your login template as well, since the template - context variable which stores the redirect path will use the value of - ``redirect_field_name`` as its key rather than ``"next"`` (the default). - - :func:`~django.contrib.auth.decorators.login_required` also takes an - optional ``login_url`` parameter. Example:: - - from django.contrib.auth.decorators import login_required - - @login_required(login_url='/accounts/login/') - def my_view(request): - ... - - Note that if you don't specify the ``login_url`` parameter, you'll need to map - the appropriate Django view to :setting:`settings.LOGIN_URL `. For - example, using the defaults, add the following line to your URLconf:: - - (r'^accounts/login/$', 'django.contrib.auth.views.login'), - - .. versionchanged:: 1.5 - - As of version 1.5 :setting:`settings.LOGIN_URL ` now also accepts - view function names and :ref:`named URL patterns `. - This allows you to freely remap your login view within your URLconf - without having to update the setting. - -.. function:: views.login(request, [template_name, redirect_field_name, authentication_form]) - - **URL name:** ``login`` - - See :doc:`the URL documentation ` for details on using - named URL patterns. - - Here's what ``django.contrib.auth.views.login`` does: - - * If called via ``GET``, it displays a login form that POSTs to the - same URL. More on this in a bit. - - * If called via ``POST``, it tries to log the user in. If login is - successful, the view redirects to the URL specified in ``next``. If - ``next`` isn't provided, it redirects to - :setting:`settings.LOGIN_REDIRECT_URL ` (which - defaults to ``/accounts/profile/``). If login isn't successful, it - redisplays the login form. - - It's your responsibility to provide the login form in a template called - ``registration/login.html`` by default. This template gets passed four - template context variables: - - * ``form``: A :class:`~django.forms.Form` object representing the login - form. See the :doc:`forms documentation ` for - more on ``Form`` objects. - - * ``next``: The URL to redirect to after successful login. This may - contain a query string, too. - - * ``site``: The current :class:`~django.contrib.sites.models.Site`, - according to the :setting:`SITE_ID` setting. If you don't have the - site framework installed, this will be set to an instance of - :class:`~django.contrib.sites.models.RequestSite`, which derives the - site name and domain from the current - :class:`~django.http.HttpRequest`. - - * ``site_name``: An alias for ``site.name``. If you don't have the site - framework installed, this will be set to the value of - :attr:`request.META['SERVER_NAME'] `. - For more on sites, see :doc:`/ref/contrib/sites`. - - If you'd prefer not to call the template :file:`registration/login.html`, - you can pass the ``template_name`` parameter via the extra arguments to - the view in your URLconf. For example, this URLconf line would use - :file:`myapp/login.html` instead:: - - (r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}), - - You can also specify the name of the ``GET`` field which contains the URL - to redirect to after login by passing ``redirect_field_name`` to the view. - By default, the field is called ``next``. - - Here's a sample :file:`registration/login.html` template you can use as a - starting point. It assumes you have a :file:`base.html` template that - defines a ``content`` block: - - .. code-block:: html+django - - {% extends "base.html" %} - - {% block content %} - - {% if form.errors %} -

Your username and password didn't match. Please try again.

- {% endif %} - -
- {% csrf_token %} - - - - - - - - - -
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
- - - -
- - {% endblock %} - - If you are using alternate authentication (see - :ref:`authentication-backends`) you can pass a custom authentication form - to the login view via the ``authentication_form`` parameter. This form must - accept a ``request`` keyword argument in its ``__init__`` method, and - provide a ``get_user`` method which returns the authenticated user object - (this method is only ever called after successful form validation). - - .. _forms documentation: ../forms/ - .. _site framework docs: ../sites/ - - .. versionadded:: 1.4 - - The :func:`~views.login` view and the :ref:`other-built-in-views` now all - return a :class:`~django.template.response.TemplateResponse` instance, - which allows you to easily customize the response data before rendering. - For more details, see the - :doc:`TemplateResponse documentation `. - -.. _other-built-in-views: - -Other built-in views --------------------- - -.. module:: django.contrib.auth.views - -In addition to the :func:`~views.login` view, the authentication system -includes a few other useful built-in views located in -:mod:`django.contrib.auth.views`: - -.. function:: logout(request, [next_page, template_name, redirect_field_name]) - - Logs a user out. - - **URL name:** ``logout`` - - See :doc:`the URL documentation ` for details on using - named URL patterns. - - **Optional arguments:** - - * ``next_page``: The URL to redirect to after logout. - - * ``template_name``: The full name of a template to display after - logging the user out. Defaults to - :file:`registration/logged_out.html` if no argument is supplied. - - * ``redirect_field_name``: The name of a ``GET`` field containing the - URL to redirect to after log out. Overrides ``next_page`` if the given - ``GET`` parameter is passed. - - **Template context:** - - * ``title``: The string "Logged out", localized. - - * ``site``: The current :class:`~django.contrib.sites.models.Site`, - according to the :setting:`SITE_ID` setting. If you don't have the - site framework installed, this will be set to an instance of - :class:`~django.contrib.sites.models.RequestSite`, which derives the - site name and domain from the current - :class:`~django.http.HttpRequest`. - - * ``site_name``: An alias for ``site.name``. If you don't have the site - framework installed, this will be set to the value of - :attr:`request.META['SERVER_NAME'] `. - For more on sites, see :doc:`/ref/contrib/sites`. - -.. function:: logout_then_login(request[, login_url]) - - Logs a user out, then redirects to the login page. - - **URL name:** No default URL provided - - **Optional arguments:** - - * ``login_url``: The URL of the login page to redirect to. - Defaults to :setting:`settings.LOGIN_URL ` if not supplied. - -.. function:: password_change(request[, template_name, post_change_redirect, password_change_form]) - - Allows a user to change their password. - - **URL name:** ``password_change`` - - **Optional arguments:** - - * ``template_name``: The full name of a template to use for - displaying the password change form. Defaults to - :file:`registration/password_change_form.html` if not supplied. - - * ``post_change_redirect``: The URL to redirect to after a successful - password change. - - * ``password_change_form``: A custom "change password" form which must - accept a ``user`` keyword argument. The form is responsible for - actually changing the user's password. Defaults to - :class:`~django.contrib.auth.forms.PasswordChangeForm`. - - **Template context:** - - * ``form``: The password change form (see ``password_change_form`` above). - -.. function:: password_change_done(request[, template_name]) - - The page shown after a user has changed their password. - - **URL name:** ``password_change_done`` - - **Optional arguments:** - - * ``template_name``: The full name of a template to use. - Defaults to :file:`registration/password_change_done.html` if not - supplied. - -.. function:: password_reset(request[, is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect, from_email]) - - Allows a user to reset their password by generating a one-time use link - that can be used to reset the password, and sending that link to the - user's registered email address. - - .. versionchanged:: 1.4 - Users flagged with an unusable password (see - :meth:`~django.contrib.auth.models.User.set_unusable_password()` - will not be able to request a password reset to prevent misuse - when using an external authentication source like LDAP. - - **URL name:** ``password_reset`` - - **Optional arguments:** - - * ``template_name``: The full name of a template to use for - displaying the password reset form. Defaults to - :file:`registration/password_reset_form.html` if not supplied. - - * ``email_template_name``: The full name of a template to use for - generating the email with the reset password link. Defaults to - :file:`registration/password_reset_email.html` if not supplied. - - * ``subject_template_name``: The full name of a template to use for - the subject of the email with the reset password link. Defaults - to :file:`registration/password_reset_subject.txt` if not supplied. - - .. versionadded:: 1.4 - - * ``password_reset_form``: Form that will be used to get the email of - the user to reset the password for. Defaults to - :class:`~django.contrib.auth.forms.PasswordResetForm`. - - * ``token_generator``: Instance of the class to check the one time link. - This will default to ``default_token_generator``, it's an instance of - ``django.contrib.auth.tokens.PasswordResetTokenGenerator``. - - * ``post_reset_redirect``: The URL to redirect to after a successful - password reset request. - - * ``from_email``: A valid email address. By default Django uses - the :setting:`DEFAULT_FROM_EMAIL`. - - **Template context:** - - * ``form``: The form (see ``password_reset_form`` above) for resetting - the user's password. - - **Email template context:** - - * ``email``: An alias for ``user.email`` - - * ``user``: The current :class:`~django.contrib.auth.models.User`, - according to the ``email`` form field. Only active users are able to - reset their passwords (``User.is_active is True``). - - * ``site_name``: An alias for ``site.name``. If you don't have the site - framework installed, this will be set to the value of - :attr:`request.META['SERVER_NAME'] `. - For more on sites, see :doc:`/ref/contrib/sites`. - - * ``domain``: An alias for ``site.domain``. If you don't have the site - framework installed, this will be set to the value of - ``request.get_host()``. - - * ``protocol``: http or https - - * ``uid``: The user's id encoded in base 36. - - * ``token``: Token to check that the reset link is valid. - - Sample ``registration/password_reset_email.html`` (email body template): - - .. code-block:: html+django - - Someone asked for password reset for email {{ email }}. Follow the link below: - {{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb36=uid token=token %} - - The same template context is used for subject template. Subject must be - single line plain text string. - - -.. function:: password_reset_done(request[, template_name]) - - The page shown after a user has been emailed a link to reset their - password. This view is called by default if the :func:`password_reset` view - doesn't have an explicit ``post_reset_redirect`` URL set. - - **URL name:** ``password_reset_done`` - - **Optional arguments:** - - * ``template_name``: The full name of a template to use. - Defaults to :file:`registration/password_reset_done.html` if not - supplied. - -.. function:: password_reset_confirm(request[, uidb36, token, template_name, token_generator, set_password_form, post_reset_redirect]) - - Presents a form for entering a new password. - - **URL name:** ``password_reset_confirm`` - - **Optional arguments:** - - * ``uidb36``: The user's id encoded in base 36. Defaults to ``None``. - - * ``token``: Token to check that the password is valid. Defaults to - ``None``. - - * ``template_name``: The full name of a template to display the confirm - password view. Default value is :file:`registration/password_reset_confirm.html`. - - * ``token_generator``: Instance of the class to check the password. This - will default to ``default_token_generator``, it's an instance of - ``django.contrib.auth.tokens.PasswordResetTokenGenerator``. - - * ``set_password_form``: Form that will be used to set the password. - Defaults to :class:`~django.contrib.auth.forms.SetPasswordForm` - - * ``post_reset_redirect``: URL to redirect after the password reset - done. Defaults to ``None``. - - **Template context:** - - * ``form``: The form (see ``set_password_form`` above) for setting the - new user's password. - - * ``validlink``: Boolean, True if the link (combination of uidb36 and - token) is valid or unused yet. - -.. function:: password_reset_complete(request[,template_name]) - - Presents a view which informs the user that the password has been - successfully changed. - - **URL name:** ``password_reset_complete`` - - **Optional arguments:** - - * ``template_name``: The full name of a template to display the view. - Defaults to :file:`registration/password_reset_complete.html`. - -Helper functions ----------------- - -.. currentmodule:: django.contrib.auth.views - -.. function:: redirect_to_login(next[, login_url, redirect_field_name]) - - Redirects to the login page, and then back to another URL after a - successful login. - - **Required arguments:** - - * ``next``: The URL to redirect to after a successful login. - - **Optional arguments:** - - * ``login_url``: The URL of the login page to redirect to. - Defaults to :setting:`settings.LOGIN_URL ` if not supplied. - - * ``redirect_field_name``: The name of a ``GET`` field containing the - URL to redirect to after log out. Overrides ``next`` if the given - ``GET`` parameter is passed. - - -.. _built-in-auth-forms: - -Built-in forms --------------- - -.. module:: django.contrib.auth.forms - -If you don't want to use the built-in views, but want the convenience of not -having to write forms for this functionality, the authentication system -provides several built-in forms located in :mod:`django.contrib.auth.forms`: - -.. class:: AdminPasswordChangeForm - - A form used in the admin interface to change a user's password. - -.. class:: AuthenticationForm - - A form for logging a user in. - -.. class:: PasswordChangeForm - - A form for allowing a user to change their password. - -.. class:: PasswordResetForm - - A form for generating and emailing a one-time use link to reset a - user's password. - -.. class:: SetPasswordForm - - A form that lets a user change his/her password without entering the old - password. - -.. class:: UserChangeForm - - A form used in the admin interface to change a user's information and - permissions. - -.. class:: UserCreationForm - - A form for creating a new user. - -Limiting access to logged-in users that pass a test ---------------------------------------------------- - -.. currentmodule:: django.contrib.auth.decorators - -To limit access based on certain permissions or some other test, you'd do -essentially the same thing as described in the previous section. - -The simple way is to run your test on :attr:`request.user -` in the view directly. For example, this view -checks to make sure the user is logged in and has the permission -``polls.can_vote``:: - - def my_view(request): - if not request.user.has_perm('polls.can_vote'): - return HttpResponse("You can't vote in this poll.") - # ... - -.. function:: user_passes_test(func, [login_url=None]) - - As a shortcut, you can use the convenient ``user_passes_test`` decorator:: - - from django.contrib.auth.decorators import user_passes_test - - @user_passes_test(lambda u: u.has_perm('polls.can_vote')) - def my_view(request): - ... - - We're using this particular test as a relatively simple example. However, - if you just want to test whether a permission is available to a user, you - can use the :func:`~django.contrib.auth.decorators.permission_required()` - decorator, described later in this document. - - :func:`~django.contrib.auth.decorators.user_passes_test` takes a required - argument: a callable that takes a - :class:`~django.contrib.auth.models.User` object and returns ``True`` if - the user is allowed to view the page. Note that - :func:`~django.contrib.auth.decorators.user_passes_test` does not - automatically check that the :class:`~django.contrib.auth.models.User` is - not anonymous. - - :func:`~django.contrib.auth.decorators.user_passes_test()` takes an - optional ``login_url`` argument, which lets you specify the URL for your - login page (:setting:`settings.LOGIN_URL ` by default). - - For example:: - - from django.contrib.auth.decorators import user_passes_test - - @user_passes_test(lambda u: u.has_perm('polls.can_vote'), login_url='/login/') - def my_view(request): - ... - -The permission_required decorator -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. function:: permission_required([login_url=None, raise_exception=False]) - - It's a relatively common task to check whether a user has a particular - permission. For that reason, Django provides a shortcut for that case: the - :func:`~django.contrib.auth.decorators.permission_required()` decorator. - Using this decorator, the earlier example can be written as:: - - from django.contrib.auth.decorators import permission_required - - @permission_required('polls.can_vote') - def my_view(request): - ... - - As for the :meth:`User.has_perm` method, permission names take the form - ``"."`` (i.e. ``polls.can_vote`` for a - permission on a model in the ``polls`` application). - - Note that :func:`~django.contrib.auth.decorators.permission_required()` - also takes an optional ``login_url`` parameter. Example:: - - from django.contrib.auth.decorators import permission_required - - @permission_required('polls.can_vote', login_url='/loginpage/') - def my_view(request): - ... - - As in the :func:`~decorators.login_required` decorator, ``login_url`` - defaults to :setting:`settings.LOGIN_URL `. - - .. versionchanged:: 1.4 - - Added ``raise_exception`` parameter. If given, the decorator will raise - :exc:`~django.core.exceptions.PermissionDenied`, prompting - :ref:`the 403 (HTTP Forbidden) view` instead of - redirecting to the login page. - -.. currentmodule:: django.contrib.auth - -Applying permissions to generic views -------------------------------------- - -To apply a permission to a :doc:`class-based generic view -`, decorate the :meth:`View.dispatch -` method on the class. See -:ref:`decorating-class-based-views` for details. - -.. _permissions: - -Permissions -=========== - -Django comes with a simple permissions system. It provides a way to assign -permissions to specific users and groups of users. - -It's used by the Django admin site, but you're welcome to use it in your own -code. - -The Django admin site uses permissions as follows: - -* Access to view the "add" form and add an object is limited to users with - the "add" permission for that type of object. -* Access to view the change list, view the "change" form and change an - object is limited to users with the "change" permission for that type of - object. -* Access to delete an object is limited to users with the "delete" - permission for that type of object. - -Permissions can be set not only per type of object, but also per specific -object instance. By using the -:meth:`~django.contrib.admin.ModelAdmin.has_add_permission`, -:meth:`~django.contrib.admin.ModelAdmin.has_change_permission` and -:meth:`~django.contrib.admin.ModelAdmin.has_delete_permission` methods provided -by the :class:`~django.contrib.admin.ModelAdmin` class, it is possible to -customize permissions for different object instances of the same type. - -Default permissions -------------------- - -When ``django.contrib.auth`` is listed in your :setting:`INSTALLED_APPS` -setting, it will ensure that three default permissions -- add, change and -delete -- are created for each Django model defined in one of your installed -applications. - -These permissions will be created when you run :djadmin:`manage.py syncdb -`; the first time you run ``syncdb`` after adding -``django.contrib.auth`` to :setting:`INSTALLED_APPS`, the default permissions -will be created for all previously-installed models, as well as for any new -models being installed at that time. Afterward, it will create default -permissions for new models each time you run :djadmin:`manage.py syncdb -`. - -Assuming you have an application with an -:attr:`~django.db.models.Options.app_label` ``foo`` and a model named ``Bar``, -to test for basic permissions you should use: - -* add: ``user.has_perm('foo.add_bar')`` -* change: ``user.has_perm('foo.change_bar')`` -* delete: ``user.has_perm('foo.delete_bar')`` - -.. _custom-permissions: - -Custom permissions ------------------- - -To create custom permissions for a given model object, use the ``permissions`` -:ref:`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:: - - 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 syncdb `. Your code is in charge of checking the -value of these permissions when an 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') - -API reference -------------- - -.. currentmodule:: django.contrib.auth.models - -.. class:: models.Permission - -Fields -~~~~~~ - -:class:`~django.contrib.auth.models.Permission` objects have the following -fields: - -.. attribute:: Permission.name - - Required. 50 characters or fewer. Example: ``'Can vote'``. - -.. attribute:: Permission.content_type - - Required. A reference to the ``django_content_type`` database table, which - contains a record for each installed Django model. - -.. attribute:: Permission.codename - - Required. 100 characters or fewer. Example: ``'can_vote'``. - -Methods -~~~~~~~ - -:class:`~django.contrib.auth.models.Permission` objects have the standard -data-access methods like any other :doc:`Django model `. - -.. currentmodule:: django.contrib.auth - -Programmatically creating permissions -------------------------------------- - -While custom permissions can be defined within a model's ``Meta`` class, you -can also create permissions directly. For example, you can create the -``can_publish`` permission for a ``BlogPost`` model in ``myapp``:: - - from django.contrib.auth.models import Group, Permission - from django.contrib.contenttypes.models import ContentType - - content_type = ContentType.objects.get(app_label='myapp', model='BlogPost') - permission = Permission.objects.create(codename='can_publish', - name='Can Publish Posts', - content_type=content_type) - -The permission can then be assigned to a -:class:`~django.contrib.auth.models.User` via its ``user_permissions`` -attribute or to a :class:`~django.contrib.auth.models.Group` via its -``permissions`` attribute. - -Authentication data in templates -================================ - -The currently logged-in user and his/her permissions are made available in the -:doc:`template context ` when you use -:class:`~django.template.context.RequestContext`. - -.. admonition:: Technicality - - Technically, these variables are only made available in the template context - if you use :class:`~django.template.context.RequestContext` *and* your - :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting contains - ``"django.contrib.auth.context_processors.auth"``, which is default. For - more, see the :ref:`RequestContext docs `. - -Users ------ - -When rendering a template :class:`~django.template.context.RequestContext`, the -currently logged-in user, either a :class:`~django.contrib.auth.models.User` -instance or an :class:`~django.contrib.auth.models.AnonymousUser` instance, is -stored in the template variable ``{{ user }}``: - -.. code-block:: html+django - - {% if user.is_authenticated %} -

Welcome, {{ user.username }}. Thanks for logging in.

- {% else %} -

Welcome, new user. Please log in.

- {% endif %} - -This template context variable is not available if a ``RequestContext`` is not -being used. - -Permissions ------------ - -The currently logged-in user's permissions are stored in the template variable -``{{ perms }}``. This is an instance of -:class:`django.contrib.auth.context_processors.PermWrapper`, which is a -template-friendly proxy of permissions. - -In the ``{{ perms }}`` object, single-attribute lookup is a proxy to -:meth:`User.has_module_perms `. -This example would display ``True`` if the logged-in user had any permissions -in the ``foo`` app:: - - {{ perms.foo }} - -Two-level-attribute lookup is a proxy to -:meth:`User.has_perm `. This example -would display ``True`` if the logged-in user had the permission -``foo.can_vote``:: - - {{ perms.foo.can_vote }} - -Thus, you can check permissions in template ``{% if %}`` statements: - -.. code-block:: html+django - - {% if perms.foo %} -

You have permission to do something in the foo app.

- {% if perms.foo.can_vote %} -

You can vote!

- {% endif %} - {% if perms.foo.can_drive %} -

You can drive!

- {% endif %} - {% else %} -

You don't have permission to do anything in the foo app.

- {% endif %} - -.. versionadded:: 1.5 - Permission lookup by "if in". - -It is possible to also look permissions up by ``{% if in %}`` statements. -For example: - -.. code-block:: html+django - - {% if 'foo' in perms %} - {% if 'foo.can_vote' in perms %} -

In lookup works, too.

- {% endif %} - {% endif %} - -Groups -====== - -Groups are a generic way of categorizing users so you can apply permissions, or -some other label, to those users. A user can belong to any number of groups. - -A user in a group automatically has the permissions granted to that group. For -example, if the group ``Site editors`` has the permission -``can_edit_home_page``, any user in that group will have that permission. - -Beyond permissions, groups are a convenient way to categorize users to give -them some label, or extended functionality. For example, you could create a -group ``'Special users'``, and you could write code that could, say, give them -access to a members-only portion of your site, or send them members-only email -messages. - -API reference -------------- - -.. class:: models.Group - -Fields -~~~~~~ - -:class:`~django.contrib.auth.models.Group` objects have the following fields: - -.. attribute:: Group.name - - Required. 80 characters or fewer. Any characters are permitted. Example: - ``'Awesome Users'``. - -.. attribute:: Group.permissions - - Many-to-many field to :class:`~django.contrib.auth.models.Permissions`:: - - group.permissions = [permission_list] - group.permissions.add(permission, permission, ...) - group.permissions.remove(permission, permission, ...) - group.permissions.clear() - -.. _auth-custom-user: - -Customizing the User model -========================== - -.. versionadded:: 1.5 - -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, and the name of the Django -model that you wish to use as your User model. - -.. admonition:: Warning - - Changing :setting:`AUTH_USER_MODEL` has a big effect on your database - structure. It changes the tables that are available, and it will affect the - construction of foreign keys and many-to-many relationships. If you intend - to set :setting:`AUTH_USER_MODEL`, you should set it before running - ``manage.py syncdb`` for the first time. - - If you have an existing project and you want to migrate to using a custom - User model, you may need to look into using a migration tool like South_ - to ease the transition. - -.. _South: http://south.aeracode.org - -Referencing the User model --------------------------- - -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. - -Instead of referring to :class:`~django.contrib.auth.models.User` directly, -you should reference the user model using -:func:`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.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) - -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. - -1. 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. - -2. 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: - -.. class:: models.CustomUser - - .. attribute:: User.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. In the following example, the field `identifier` is used - as the identifying field:: - - class MyUser(AbstractBaseUser): - identifier = models.CharField(max_length=40, unique=True, db_index=True) - ... - USERNAME_FIELD = 'identifier' - - .. attribute:: User.REQUIRED_FIELDS - - A list of the field names that *must* be provided when creating - a user. 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``. - - .. attribute:: User.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:`attribute on the builtin user model - ` for details. - - .. method:: User.get_full_name(): - - A longer formal identifier for the user. A common interpretation - would be the full name name of the user, but it can be any string that - identifies the user. - - .. method:: User.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.User.get_full_name()`. - -The following methods are available on any subclass of -:class:`~django.contrib.auth.models.AbstractBaseUser`: - -.. class:: models.AbstractBaseUser - - .. method:: models.AbstractBaseUser.get_username() - - Returns the value of the field nominated by ``USERNAME_FIELD``. - - .. method:: models.AbstractBaseUser.is_anonymous() - - Always returns ``False``. This is a way of differentiating - from :class:`~django.contrib.auth.models.AnonymousUser` objects. - Generally, you should prefer using - :meth:`~django.contrib.auth.models.AbstractBaseUser.is_authenticated()` to this - method. - - .. method:: models.AbstractBaseUser.is_authenticated() - - Always returns ``True``. 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 - it only indicates that the user has provided a - valid username and password. - - .. 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. - - .. 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. - - -You should also define a custom manager for your User model. If your User -model defines `username` and `email` 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 will 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 - fields, 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 - fields, 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 provider a password. - -:class:`~django.contrib.auth.models.BaseUserManager` provides the following -utility methods: - -.. class:: models.BaseUserManager - - .. method:: models.BaseUserManager.normalize_email(email) - - A classmethod that 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`` (uppercase letter o, lowercase 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 can -simply subclass :class:`~django.contrib.auth.models.AbstractUser` and add your -custom profile fields. - -Custom users and the built-in auth forms -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -As you may expect, built-in Django's :ref:`forms ` -and :ref:`views ` make certain assumptions about -the user model that they are working with. - -If your user model doesn't follow the same assumptions, it may be necessary to define -a replacement form, and pass that form in as part of the configuration of the -auth views. - -* :class:`~django.contrib.auth.forms.UserCreationForm` - - Depends on the :class:`~django.contrib.auth.models.User` model. - Must be re-written for any custom user model. - -* :class:`~django.contrib.auth.forms.UserChangeForm` - - Depends on the :class:`~django.contrib.auth.models.User` model. - Must be re-written for any custom user model. - -* :class:`~django.contrib.auth.forms.AuthenticationForm` - - Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser`, - and will adapt to use the field defined in `USERNAME_FIELD`. - -* :class:`~django.contrib.auth.forms.PasswordResetForm` - - Assumes that the user model has an integer primary key, has a field named - `email` that can be used to identify the user, and a boolean field - named `is_active` to prevent password resets for inactive users. - -* :class:`~django.contrib.auth.forms.SetPasswordForm` - - Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` - -* :class:`~django.contrib.auth.forms.PasswordChangeForm` - - Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` - -* :class:`~django.contrib.auth.forms.AdminPasswordChangeForm` - - Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` - - -Custom users and django.contrib.admin -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you want your custom User model to also work with 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: - -.. attribute:: User.is_staff - - Returns True if the user is allowed to have access to the admin site. - -.. attribute:: User.is_active - - Returns True if the user account is currently active. - -.. method:: User.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:: User.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 :class:`~django.contrib.auth.models.AbstractUser`, -you can use Django's existing :class:`~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 -:class:`~django.contrib.auth.admin.UserAdmin`; however, you'll need to -override any of the definitions that refer to fields on -:class:`~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.model.PermissionsMixin`. -This is an abstract model you can include in the class heirarchy for your User -model, giving you all the methods and database fields necessary to support -Django's permission model. - -:class:`~django.contrib.auth.model.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 his/her - 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 ``"."`` (see - `permissions`_). 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 - ``"."``. 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:: ModelBackend - - If you don't include the - :class:`~django.contrib.auth.model.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 will 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 is currently in use in your project, or merge your proxy's -behavior into your User subclass. - -Custom users and signals -~~~~~~~~~~~~~~~~~~~~~~~~ - -Another limitation of custom User models is that you can't use -:func:`django.contrib.auth.get_user_model()` as the sender or target of a signal -handler. Instead, you must register the handler with the actual User model. - -Custom users and testing/fixtures -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you are writing an application that interacts with the User model, you must -take some precautions to ensure that your test suite will run regardless of -the User model that is being used by a project. Any test that instantiates an -instance of User will fail if the User model has been swapped out. This -includes any attempt to create an instance of User with a fixture. - -To ensure that your test suite will pass in any project configuration, -``django.contrib.auth.tests.utils`` defines a ``@skipIfCustomUser`` decorator. -This decorator will cause a test case to be skipped if any User model other -than the default Django user is in use. This decorator can be applied to a -single test, or to an entire test class. - -Depending on your application, tests may also be needed to be added to ensure -that the application works with *any* user model, not just the default User -model. To assist with this, Django provides two substitute user models that -can be used in test suites: - -* :class:`django.contrib.auth.tests.custom_user.CustomUser`, a custom user - model that uses an ``email`` field as the username, and has a basic - admin-compliant permissions setup - -* :class:`django.contrib.auth.tests.custom_user.ExtensionUser`, a custom - user model that extends :class:`~django.contrib.auth.models.AbstractUser`, - adding a ``date_of_birth`` field. - -You can then use the ``@override_settings`` decorator to make that test run -with the custom User model. For example, here is a skeleton for a test that -would test three possible User models -- the default, plus the two User -models provided by ``auth`` app:: - - from django.contrib.auth.tests.utils import skipIfCustomUser - from django.test import TestCase - from django.test.utils import override_settings - - - class ApplicationTestCase(TestCase): - @skipIfCustomUser - def test_normal_user(self): - "Run tests for the normal user model" - self.assertSomething() - - @override_settings(AUTH_USER_MODEL='auth.CustomUser') - def test_custom_user(self): - "Run tests for a custom user model with email-based authentication" - self.assertSomething() - - @override_settings(AUTH_USER_MODEL='auth.ExtensionUser') - def test_extension_user(self): - "Run tests for a simple extension of the built-in User." - self.assertSomething() - - -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 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=MyUserManager.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, - db_index=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 __unicode__(self): - 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 - 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 - - 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 MyUserAdmin(UserAdmin): - # 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',)}), - ('Important dates', {'fields': ('last_login',)}), - ) - 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, MyUserAdmin) - # ... and, since we're not using Django's builtin permissions, - # unregister the Group model from admin. - admin.site.unregister(Group) - -.. _authentication-backends: - -Other authentication sources -============================ - -The authentication that comes with Django is good enough for most common cases, -but you may 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 :doc:`authentication backend 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 ` above -- 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 tuple 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 builtin 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. - -.. 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(**credentials)``, as well as a set of -optional permission related :ref:`authorization methods `. - -The ``get_user`` method takes a ``user_id`` -- which could be a username, -database ID or whatever -- and returns a ``User`` object. - -The ``authenticate`` method takes credentials as keyword arguments. Most of -the time, it'll just look like this:: - - class MyBackend(object): - def authenticate(self, 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, token=None): - # Check the token and return a User. - -Either way, ``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 ``None``. - -The Django admin system is tightly coupled to the Django ``User`` object -described at the beginning of this document. 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:: - - from django.conf import settings - from django.contrib.auth.models import User, check_password - - 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 = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de' - """ - - def authenticate(self, 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. Note that we can set password - # to anything, because it won't be checked; the password - # from settings.py will. - user = User(username=username, password='get from settings.py') - 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 - -.. _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. - -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): - if user_obj.username == settings.ADMIN_LOGIN: - return True - else: - return False - -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 inheritence 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 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 :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 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. - - -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. diff --git a/docs/topics/auth/customizing.txt b/docs/topics/auth/customizing.txt new file mode 100644 index 00000000000..7c17d26b474 --- /dev/null +++ b/docs/topics/auth/customizing.txt @@ -0,0 +1,1068 @@ +==================================== +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 extendible or replaceable. This document provides details +about how the auth system can be customized. + +:ref:`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 ` that can be +checked through Django's authorization system. + +You can :ref:`extend ` the default User model, or :ref:`substitute +` 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 `authentication backend 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 ` above -- 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 tuple 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. + +.. 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(**credentials)``, as well as a set of +optional permission related :ref:`authorization methods `. + +The ``get_user`` method takes a ``user_id`` -- which could be a username, +database ID or whatever -- and returns a ``User`` object. + +The ``authenticate`` method takes credentials as keyword arguments. Most of +the time, it'll just look like this:: + + class MyBackend(object): + def authenticate(self, 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, token=None): + # Check the token and return a User. + +Either way, ``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 ``None``. + +The Django admin system is tightly coupled to the Django ``User`` object +described at the beginning of this document. 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:: + + from django.conf import settings + from django.contrib.auth.models import User, check_password + + 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 = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de' + """ + + def authenticate(self, 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. Note that we can set password + # to anything, because it won't be checked; the password + # from settings.py will. + user = User(username=username, password='get from settings.py') + 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 + +.. _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. + +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): + if user_obj.username == settings.ADMIN_LOGIN: + return True + else: + return False + +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 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 :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 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. + + +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 `. + +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 syncdb `. Your code is in charge of checking the +value of these permissions when an 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 +` 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 :ref:`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:: + + from django.contrib.auth.models import User + + class Employee(models.Model): + user = models.OneToOneField(User) + 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 + 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(UserAdmin): + 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 do not get +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. + +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. + +.. _auth-profiles: + +.. deprecated:: 1.5 + With the introduction of :ref:`custom User models `, + the use of :setting:`AUTH_PROFILE_MODULE` to define a single profile + model is no longer supported. See the + :doc:`Django 1.5 release notes` for more information. + +Prior to 1.5, a single profile model could be specified site-wide with the +setting :setting:`AUTH_PROFILE_MODULE` with a string consisting of the +following items, separated by a dot: + +1. The name of the application (case sensitive) in which the user + profile model is defined (in other words, the + name which was passed to :djadmin:`manage.py startapp ` to create + the application). + +2. The name of the model (not case sensitive) class. + +For example, if the profile model was a class named ``UserProfile`` and was +defined inside an application named ``accounts``, the appropriate setting would +be:: + + AUTH_PROFILE_MODULE = 'accounts.UserProfile' + +When a user profile model has been defined and specified in this manner, each +:class:`~django.contrib.auth.models.User` object will have a method -- +:class:`~django.contrib.auth.models.User.get_profile()` -- which returns the +instance of the user profile model associated with that +:class:`~django.contrib.auth.models.User`. + +The method :class:`~django.contrib.auth.models.User.get_profile()` +does not create a profile if one does not exist. + +.. _auth-custom-user: + +Substituting a custom User model +================================ + +.. versionadded:: 1.5 + +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, and the name of the Django +model that you wish to use as your User model. + +.. admonition:: Warning + + Changing :setting:`AUTH_USER_MODEL` has a big effect on your database + structure. It changes the tables that are available, and it will affect the + construction of foreign keys and many-to-many relationships. If you intend + to set :setting:`AUTH_USER_MODEL`, you should set it before running + ``manage.py syncdb`` for the first time. + + If you have an existing project and you want to migrate to using a custom + User model, you may need to look into using a migration tool like South_ + to ease the transition. + +.. _South: http://south.aeracode.org + +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) + +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. + +1. 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. + +2. 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. In the following example, the field `identifier` is used + as the identifying field:: + + class MyUser(AbstractBaseUser): + identifier = models.CharField(max_length=40, unique=True, db_index=True) + ... + USERNAME_FIELD = 'identifier' + + .. attribute:: REQUIRED_FIELDS + + A list of the field names that *must* be provided when creating + a user. 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``. + + .. 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:`attribute on the builtin user model + ` for details. + + .. method:: get_full_name() + + A longer formal identifier for the user. A common interpretation + would be the full name 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()`. + +The following 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:: models.AbstractBaseUser.is_anonymous() + + Always returns ``False``. This is a way of differentiating + from :class:`~django.contrib.auth.models.AnonymousUser` objects. + Generally, you should prefer using + :meth:`~django.contrib.auth.models.AbstractBaseUser.is_authenticated()` to this + method. + + .. method:: models.AbstractBaseUser.is_authenticated() + + Always returns ``True``. 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 - it only indicates that the user has provided a + valid username and password. + + .. 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. + + .. 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. + +You should also define a custom manager for your User model. If your User +model defines `username` and `email` 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 will 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 + fields, 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 + fields, 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 provider a password. + +:class:`~django.contrib.auth.models.BaseUserManager` provides the following +utility methods: + +.. class:: models.BaseUserManager + + .. method:: models.BaseUserManager.normalize_email(email) + + A classmethod that 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`` (uppercase letter o, lowercase 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 can +simply subclass ``django.contrib.auth.models.AbstractUser`` and add your +custom profile fields. This class provides the full implementation of the +default :class:`~django.contrib.auth.models.User` as an :ref:`abstract model +`. + +Custom users and the built-in auth forms +---------------------------------------- + +As you may expect, built-in Django's :ref:`forms ` and +:ref:`views ` make certain assumptions about the user +model that they are working with. + +If your user model doesn't follow the same assumptions, it may be necessary to define +a replacement form, and pass that form in as part of the configuration of the +auth views. + +* :class:`~django.contrib.auth.forms.UserCreationForm` + + Depends on the :class:`~django.contrib.auth.models.User` model. + Must be re-written for any custom user model. + +* :class:`~django.contrib.auth.forms.UserChangeForm` + + Depends on the :class:`~django.contrib.auth.models.User` model. + Must be re-written for any custom user model. + +* :class:`~django.contrib.auth.forms.AuthenticationForm` + + Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser`, + and will adapt to use the field defined in `USERNAME_FIELD`. + +* :class:`~django.contrib.auth.forms.PasswordResetForm` + + Assumes that the user model has an integer primary key, has a field named + `email` that can be used to identify the user, and a boolean field + named `is_active` to prevent password resets for inactive users. + +* :class:`~django.contrib.auth.forms.SetPasswordForm` + + Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` + +* :class:`~django.contrib.auth.forms.PasswordChangeForm` + + Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` + +* :class:`~django.contrib.auth.forms.AdminPasswordChangeForm` + + Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` + + +Custom users and django.contrib.admin +------------------------------------- + +If you want your custom User model to also work with 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 his/her + 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 ``"."`` (see + :ref:`permissions `). 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 + ``"."``. 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:: 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 will 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 is currently in use in your project, or merge your proxy's +behavior into your User subclass. + +Custom users and signals +------------------------ + +Another limitation of custom User models is that you can't use +:func:`django.contrib.auth.get_user_model()` as the sender or target of a signal +handler. Instead, you must register the handler with the resulting User model. +See :doc:`/topics/signals` for more information on registering an sending +signals. + +Custom users and testing/fixtures +--------------------------------- + +If you are writing an application that interacts with the User model, you must +take some precautions to ensure that your test suite will run regardless of +the User model that is being used by a project. Any test that instantiates an +instance of User will fail if the User model has been swapped out. This +includes any attempt to create an instance of User with a fixture. + +To ensure that your test suite will pass in any project configuration, +``django.contrib.auth.tests.utils`` defines a ``@skipIfCustomUser`` decorator. +This decorator will cause a test case to be skipped if any User model other +than the default Django user is in use. This decorator can be applied to a +single test, or to an entire test class. + +Depending on your application, tests may also be needed to be added to ensure +that the application works with *any* user model, not just the default User +model. To assist with this, Django provides two substitute user models that +can be used in test suites: + +* ``django.contrib.auth.tests.custom_user.CustomUser``, a custom user + model that uses an ``email`` field as the username, and has a basic + admin-compliant permissions setup + +* ``django.contrib.auth.tests.custom_user.ExtensionUser``, a custom + user model that extends ``django.contrib.auth.models.AbstractUser``, + adding a ``date_of_birth`` field. + +You can then use the ``@override_settings`` decorator to make that test run +with the custom User model. For example, here is a skeleton for a test that +would test three possible User models -- the default, plus the two User +models provided by ``auth`` app:: + + from django.contrib.auth.tests.utils import skipIfCustomUser + from django.test import TestCase + from django.test.utils import override_settings + + + class ApplicationTestCase(TestCase): + @skipIfCustomUser + def test_normal_user(self): + "Run tests for the normal user model" + self.assertSomething() + + @override_settings(AUTH_USER_MODEL='auth.CustomUser') + def test_custom_user(self): + "Run tests for a custom user model with email-based authentication" + self.assertSomething() + + @override_settings(AUTH_USER_MODEL='auth.ExtensionUser') + def test_extension_user(self): + "Run tests for a simple extension of the built-in User." + self.assertSomething() + + +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 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=MyUserManager.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, + db_index=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 __unicode__(self): + 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 + 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 + + 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 MyUserAdmin(UserAdmin): + # 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',)}), + ('Important dates', {'fields': ('last_login',)}), + ) + 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, MyUserAdmin) + # ... and, since we're not using Django's builtin permissions, + # unregister the Group model from admin. + admin.site.unregister(Group) diff --git a/docs/topics/auth/default.txt b/docs/topics/auth/default.txt new file mode 100644 index 00000000000..c4736135b0c --- /dev/null +++ b/docs/topics/auth/default.txt @@ -0,0 +1,1077 @@ +====================================== +Using the Django authentication system +====================================== + +.. currentmodule:: django.contrib.auth + +This document explains the usage of Django's authentication system in its +default configuration. This configuration has evolved to serve the most common +project needs, handling a reasonably wide range of tasks, and has a careful +implementation of passwords and permissions, and can handle many projects as +is. For projects where authentication needs differ from the default, Django +supports extensive :doc:`extension and customization +` of authentication. + +Django authentication provides both authentication and authorization, together +and is generally referred to as the authentication system, as these features +somewhat coupled. + +.. _user-objects: + +User objects +============ + +:class:`~django.contrib.auth.models.User` objects are the core of the +authentication system. They typically represent the people interacting with +your site and are used to enable things like restricting access, registering +user profiles, associating content with creators etc. Only one class of user +exists in Django's authentication framework, i.e., 'superusers' or admin +'staff' users are is just a user objects with special attributes set, not +different classes of user objects. + +The primary attributes of the default user are: + +* username +* password +* email +* first name +* last name + +See the :class:`full API documentation ` for +full reference, the documentation that follows is more task oriented. + +.. _topics-auth-creating-users: + +Creating users +-------------- + +The most direct way to create users is to use the included +:meth:`~django.contrib.auth.models.UserManager.create_user` helper function:: + + >>> from django.contrib.auth.models import User + >>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword') + + # At this point, user is a User object that has already been saved + # to the database. You can continue to change its attributes + # if you want to change other fields. + >>> user.last_name = 'Lennon' + >>> user.save() + +If you have the Django admin installed, you can also :ref:`create users +interactively `. + +.. _topics-auth-creating-superusers: + +Creating superusers +------------------- + +:djadmin:`manage.py syncdb ` prompts you to create a superuser the +first time you run it with ``'django.contrib.auth'`` in your +:setting:`INSTALLED_APPS`. If you need to create a superuser at a later date, +you can use a command line utility:: + + manage.py createsuperuser --username=joe --email=joe@example.com + +You will be prompted for a password. After you enter one, the user will be +created immediately. If you leave off the :djadminopt:`--username` or the +:djadminopt:`--email` options, it will prompt you for those values. + +Changing passwords +------------------ + +Django does not store raw (clear text) passwords on the user model, but only +a hash (see :doc:`documentation of how passwords are managed +` for full details). Because of this, do not attempt to +manipulate the password attribute of the user directly. This is why a a helper +function is used when creating a user. + +To change a user's password, you have several options: + +:djadmin:`manage.py changepassword *username* ` offers a method +of changing a User's password from the command line. It prompts you to +change the password of a given user which you must enter twice. If +they both match, the new password will be changed immediately. If you +do not supply a user, the command will attempt to change the password +whose username matches the current system user. + +You can also change a password programmatically, using +:meth:`~django.contrib.auth.models.User.set_password()`: + +.. code-block:: python + + >>> from django.contrib.auth.models import User + >>> u = User.objects.get(username__exact='john') + >>> u.set_password('new password') + >>> u.save() + +If you have the Django admin installed, you can also change user's passwords +on the :ref:`authentication system's admin pages `. + +Django also provides :ref:`views ` and :ref:`forms +` that may be used to allow users to change their own +passwords. + +Authenticating Users +-------------------- + +.. function:: authenticate(\**credentials) + + To authenticate a given username and password, use + :func:`~django.contrib.auth.authenticate()`. It takes credentials in the + form of keyword arguments, for the default configuration this is + ``username`` and ``password``, and it returns + a :class:`~django.contrib.auth.models.User` object if the password is valid + for the given username. If the password is invalid, + :func:`~django.contrib.auth.authenticate()` returns ``None``. Example:: + + from django.contrib.auth import authenticate + user = authenticate(username='john', password='secret') + if user is not None: + # the password verified for the user + if user.is_active: + print("User is valid, active and authenticated") + else: + print("The password is valid, but the account has been disabled!") + else: + # the authentication system was unable to verify the username and password + print("The username and password were incorrect.") + +.. _topic-authorization: + +Permissions and Authorization +============================= + +Django comes with a simple permissions system. It provides a way to assign +permissions to specific users and groups of users. + +It's used by the Django admin site, but you're welcome to use it in your own +code. + +The Django admin site uses permissions as follows: + +* Access to view the "add" form and add an object is limited to users with + the "add" permission for that type of object. +* Access to view the change list, view the "change" form and change an + object is limited to users with the "change" permission for that type of + object. +* Access to delete an object is limited to users with the "delete" + permission for that type of object. + +Permissions can be set not only per type of object, but also per specific +object instance. By using the +:meth:`~django.contrib.admin.ModelAdmin.has_add_permission`, +:meth:`~django.contrib.admin.ModelAdmin.has_change_permission` and +:meth:`~django.contrib.admin.ModelAdmin.has_delete_permission` methods provided +by the :class:`~django.contrib.admin.ModelAdmin` class, it is possible to +customize permissions for different object instances of the same type. + +:class:`~django.contrib.auth.models.User` objects have two many-to-many +fields: ``groups`` and ``user_permissions``. +:class:`~django.contrib.auth.models.User` objects can access their related +objects in the same way as any other :doc:`Django model +`: + +.. code-block:: python + + myuser.groups = [group_list] + myuser.groups.add(group, group, ...) + myuser.groups.remove(group, group, ...) + myuser.groups.clear() + myuser.user_permissions = [permission_list] + myuser.user_permissions.add(permission, permission, ...) + myuser.user_permissions.remove(permission, permission, ...) + myuser.user_permissions.clear() + +Default permissions +------------------- + +When ``django.contrib.auth`` is listed in your :setting:`INSTALLED_APPS` +setting, it will ensure that three default permissions -- add, change and +delete -- are created for each Django model defined in one of your installed +applications. + +These permissions will be created when you run :djadmin:`manage.py syncdb +`; the first time you run ``syncdb`` after adding +``django.contrib.auth`` to :setting:`INSTALLED_APPS`, the default permissions +will be created for all previously-installed models, as well as for any new +models being installed at that time. Afterward, it will create default +permissions for new models each time you run :djadmin:`manage.py syncdb +`. + +Assuming you have an application with an +:attr:`~django.db.models.Options.app_label` ``foo`` and a model named ``Bar``, +to test for basic permissions you should use: + +* add: ``user.has_perm('foo.add_bar')`` +* change: ``user.has_perm('foo.change_bar')`` +* delete: ``user.has_perm('foo.delete_bar')`` + +The :class:`~django.contrib.auth.models.Permission` model is rarely accessed +directly. + +Groups +------ + +:class:`django.contrib.auth.models.Group` models are a generic way of +categorizing users so you can apply permissions, or some other label, to those +users. A user can belong to any number of groups. + +A user in a group automatically has the permissions granted to that group. For +example, if the group ``Site editors`` has the permission +``can_edit_home_page``, any user in that group will have that permission. + +Beyond permissions, groups are a convenient way to categorize users to give +them some label, or extended functionality. For example, you could create a +group ``'Special users'``, and you could write code that could, say, give them +access to a members-only portion of your site, or send them members-only email +messages. + +Programmatically creating permissions +------------------------------------- + +While :ref:`custom permissions ` can be defined within +a model's ``Meta`` class, you can also create permissions directly. For +example, you can create the ``can_publish`` permission for a ``BlogPost`` model +in ``myapp``:: + + from django.contrib.auth.models import Group, Permission + from django.contrib.contenttypes.models import ContentType + + content_type = ContentType.objects.get(app_label='myapp', model='BlogPost') + permission = Permission.objects.create(codename='can_publish', + name='Can Publish Posts', + content_type=content_type) + +The permission can then be assigned to a +:class:`~django.contrib.auth.models.User` via its ``user_permissions`` +attribute or to a :class:`~django.contrib.auth.models.Group` via its +``permissions`` attribute. + +.. _auth-web-requests: + +Authentication in Web requests +============================== + +Django uses :doc:`sessions ` and middleware to hook the +authentication system into :class:`request objects `. + +These provide a :attr:`request.user ` attribute +on every request which represents the current user. If the current user has not +logged in, this attribute will be set to an instance +of :class:`~django.contrib.auth.models.AnonymousUser`, otherwise it will be an +instance of :class:`~django.contrib.auth.models.User`. + +You can tell them apart with +:meth:`~django.contrib.auth.models.User.is_authenticated()`, like so:: + + if request.user.is_authenticated(): + # Do something for authenticated users. + else: + # Do something for anonymous users. + +.. _how-to-log-a-user-in: + +How to log a user in +-------------------- + +If you have an authenticated user you want to attach to the current session +- this is done with a :func:`~django.contrib.auth.login` function. + +.. function:: login() + + To log a user in, from a view, use :func:`~django.contrib.auth.login()`. It + takes an :class:`~django.http.HttpRequest` object and a + :class:`~django.contrib.auth.models.User` object. + :func:`~django.contrib.auth.login()` saves the user's ID in the session, + using Django's session framework. + + Note that any data set during the anonymous session is retained in the + session after a user logs in. + + This example shows how you might use both + :func:`~django.contrib.auth.authenticate()` and + :func:`~django.contrib.auth.login()`:: + + from django.contrib.auth import authenticate, login + + def my_view(request): + username = request.POST['username'] + password = request.POST['password'] + user = authenticate(username=username, password=password) + if user is not None: + if user.is_active: + login(request, user) + # Redirect to a success page. + else: + # Return a 'disabled account' error message + else: + # Return an 'invalid login' error message. + +.. admonition:: Calling ``authenticate()`` first + + When you're manually logging a user in, you *must* call + :func:`~django.contrib.auth.authenticate()` before you call + :func:`~django.contrib.auth.login()`. + :func:`~django.contrib.auth.authenticate()` + sets an attribute on the :class:`~django.contrib.auth.models.User` noting + which authentication backend successfully authenticated that user (see the + :ref:`backends documentation ` for details), and + this information is needed later during the login process. An error will be + raise if you try to login a user object retrieved from the database + directly. + +How to log a user out +--------------------- + +.. function:: logout() + + To log out a user who has been logged in via + :func:`django.contrib.auth.login()`, use + :func:`django.contrib.auth.logout()` within your view. It takes an + :class:`~django.http.HttpRequest` object and has no return value. + Example:: + + from django.contrib.auth import logout + + def logout_view(request): + logout(request) + # Redirect to a success page. + + Note that :func:`~django.contrib.auth.logout()` doesn't throw any errors if + the user wasn't logged in. + + When you call :func:`~django.contrib.auth.logout()`, the session data for + the current request is completely cleaned out. All existing data is + removed. This is to prevent another person from using the same Web browser + to log in and have access to the previous user's session data. If you want + to put anything into the session that will be available to the user + immediately after logging out, do that *after* calling + :func:`django.contrib.auth.logout()`. + +Limiting access to logged-in users +---------------------------------- + +The raw way +~~~~~~~~~~~ + +The simple, raw way to limit access to pages is to check +:meth:`request.user.is_authenticated() +` and either redirect to a +login page:: + + from django.shortcuts import redirect + + def my_view(request): + if not request.user.is_authenticated(): + return redirect('/login/?next=%s' % request.path) + # ... + +...or display an error message:: + + from django.shortcuts import render + + def my_view(request): + if not request.user.is_authenticated(): + return render('myapp/login_error.html') + # ... + +.. currentmodule:: django.contrib.auth.decorators + +The login_required decorator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. function:: login_required([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None]) + + As a shortcut, you can use the convenient + :func:`~django.contrib.auth.decorators.login_required` decorator:: + + from django.contrib.auth.decorators import login_required + + @login_required + def my_view(request): + ... + + :func:`~django.contrib.auth.decorators.login_required` does the following: + + * If the user isn't logged in, redirect to + :setting:`settings.LOGIN_URL `, passing the current absolute + path in the query string. Example: ``/accounts/login/?next=/polls/3/``. + + * If the user is logged in, execute the view normally. The view code is + free to assume the user is logged in. + + By default, the path that the user should be redirected to upon + successful authentication is stored in a query string parameter called + ``"next"``. If you would prefer to use a different name for this parameter, + :func:`~django.contrib.auth.decorators.login_required` takes an + optional ``redirect_field_name`` parameter:: + + from django.contrib.auth.decorators import login_required + + @login_required(redirect_field_name='my_redirect_field') + def my_view(request): + ... + + Note that if you provide a value to ``redirect_field_name``, you will most + likely need to customize your login template as well, since the template + context variable which stores the redirect path will use the value of + ``redirect_field_name`` as its key rather than ``"next"`` (the default). + + :func:`~django.contrib.auth.decorators.login_required` also takes an + optional ``login_url`` parameter. Example:: + + from django.contrib.auth.decorators import login_required + + @login_required(login_url='/accounts/login/') + def my_view(request): + ... + + Note that if you don't specify the ``login_url`` parameter, you'll need to + ensure that the :setting:`settings.LOGIN_URL ` and your login + view are properly associated. For example, using the defaults, add the + following line to your URLconf:: + + (r'^accounts/login/$', 'django.contrib.auth.views.login'), + + .. versionchanged:: 1.5 + + The :setting:`settings.LOGIN_URL ` also accepts + view function names and :ref:`named URL patterns `. + This allows you to freely remap your login view within your URLconf + without having to update the setting. + +.. note:: + + The login_required decorator does NOT check the is_active flag on a user. + +Limiting access to logged-in users that pass a test +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To limit access based on certain permissions or some other test, you'd do +essentially the same thing as described in the previous section. + +The simple way is to run your test on :attr:`request.user +` in the view directly. For example, this view +checks to make sure the user has an email in the desired domain:: + + def my_view(request): + if not '@example.com' in request.user.email: + return HttpResponse("You can't vote in this poll.") + # ... + +.. function:: user_passes_test(func, [login_url=None]) + + As a shortcut, you can use the convenient ``user_passes_test`` decorator:: + + from django.contrib.auth.decorators import user_passes_test + + def email_check(user): + return '@example.com' in request.user.email + + @user_passes_test(email_check) + def my_view(request): + ... + + :func:`~django.contrib.auth.decorators.user_passes_test` takes a required + argument: a callable that takes a + :class:`~django.contrib.auth.models.User` object and returns ``True`` if + the user is allowed to view the page. Note that + :func:`~django.contrib.auth.decorators.user_passes_test` does not + automatically check that the :class:`~django.contrib.auth.models.User` is + not anonymous. + + :func:`~django.contrib.auth.decorators.user_passes_test()` takes an + optional ``login_url`` argument, which lets you specify the URL for your + login page (:setting:`settings.LOGIN_URL ` by default). + + For example:: + + @user_passes_test(email_check, login_url='/login/') + def my_view(request): + ... + +The permission_required decorator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. function:: permission_required([login_url=None, raise_exception=False]) + + It's a relatively common task to check whether a user has a particular + permission. For that reason, Django provides a shortcut for that case: the + :func:`~django.contrib.auth.decorators.permission_required()` decorator.:: + + from django.contrib.auth.decorators import permission_required + + @permission_required('polls.can_vote') + def my_view(request): + ... + + As for the :meth:`~django.contrib.auth.models.User.has_perm` method, + permission names take the form ``"."`` + (i.e. ``polls.can_vote`` for a permission on a model in the ``polls`` + application). + + Note that :func:`~django.contrib.auth.decorators.permission_required()` + also takes an optional ``login_url`` parameter. Example:: + + from django.contrib.auth.decorators import permission_required + + @permission_required('polls.can_vote', login_url='/loginpage/') + def my_view(request): + ... + + As in the :func:`~django.contrib.auth.decorators.login_required` decorator, + ``login_url`` defaults to :setting:`settings.LOGIN_URL `. + + .. versionchanged:: 1.4 + + Added ``raise_exception`` parameter. If given, the decorator will raise + :exc:`~django.core.exceptions.PermissionDenied`, prompting + :ref:`the 403 (HTTP Forbidden) view` instead of + redirecting to the login page. + +Applying permissions to generic views +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To apply a permission to a :doc:`class-based generic view +`, decorate the :meth:`View.dispatch +` method on the class. See +:ref:`decorating-class-based-views` for details. + + +.. _built-in-auth-views: + +Authentication Views +-------------------- + +.. module:: django.contrib.auth.views + +Django provides several views that you can use for handling login, logout, and +password management. These make use of the :ref:`stock auth forms +` but you can pass in your own forms as well. + +Django provides no default template for the authentication views - however the +template context is documented for each view below. + +.. versionadded:: 1.4 + +The built-in views all return +a :class:`~django.template.response.TemplateResponse` instance, which allows +you to easily customize the response data before rendering. For more details, +see the :doc:`TemplateResponse documentation `. + +Most built-in authentication views provide a URL name for easier reference. See +:doc:`the URL documentation ` for details on using named URL +patterns. + + +.. function:: login(request, [template_name, redirect_field_name, authentication_form]) + + **URL name:** ``login`` + + See :doc:`the URL documentation ` for details on using + named URL patterns. + + Here's what ``django.contrib.auth.views.login`` does: + + * If called via ``GET``, it displays a login form that POSTs to the + same URL. More on this in a bit. + + * If called via ``POST`` with user submitted credentials, it tries to log + the user in. If login is successful, the view redirects to the URL + specified in ``next``. If ``next`` isn't provided, it redirects to + :setting:`settings.LOGIN_REDIRECT_URL ` (which + defaults to ``/accounts/profile/``). If login isn't successful, it + redisplays the login form. + + It's your responsibility to provide the html for the login template + , called ``registration/login.html`` by default. This template gets passed + four template context variables: + + * ``form``: A :class:`~django.forms.Form` object representing the + :class:`~django.contrib.auth.forms.AuthenticationForm`. + + * ``next``: The URL to redirect to after successful login. This may + contain a query string, too. + + * ``site``: The current :class:`~django.contrib.sites.models.Site`, + according to the :setting:`SITE_ID` setting. If you don't have the + site framework installed, this will be set to an instance of + :class:`~django.contrib.sites.models.RequestSite`, which derives the + site name and domain from the current + :class:`~django.http.HttpRequest`. + + * ``site_name``: An alias for ``site.name``. If you don't have the site + framework installed, this will be set to the value of + :attr:`request.META['SERVER_NAME'] `. + For more on sites, see :doc:`/ref/contrib/sites`. + + If you'd prefer not to call the template :file:`registration/login.html`, + you can pass the ``template_name`` parameter via the extra arguments to + the view in your URLconf. For example, this URLconf line would use + :file:`myapp/login.html` instead:: + + (r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}), + + You can also specify the name of the ``GET`` field which contains the URL + to redirect to after login by passing ``redirect_field_name`` to the view. + By default, the field is called ``next``. + + Here's a sample :file:`registration/login.html` template you can use as a + starting point. It assumes you have a :file:`base.html` template that + defines a ``content`` block: + + .. code-block:: html+django + + {% extends "base.html" %} + + {% block content %} + + {% if form.errors %} +

Your username and password didn't match. Please try again.

+ {% endif %} + +
+ {% csrf_token %} + + + + + + + + + +
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
+ + + +
+ + {% endblock %} + + If you have customized authentication (see + :doc:`Customizing Authentication `) you can pass a custom authentication form + to the login view via the ``authentication_form`` parameter. This form must + accept a ``request`` keyword argument in its ``__init__`` method, and + provide a ``get_user`` method which returns the authenticated user object + (this method is only ever called after successful form validation). + + .. _forms documentation: ../forms/ + .. _site framework docs: ../sites/ + + +.. function:: logout(request, [next_page, template_name, redirect_field_name]) + + Logs a user out. + + **URL name:** ``logout`` + + **Optional arguments:** + + * ``next_page``: The URL to redirect to after logout. + + * ``template_name``: The full name of a template to display after + logging the user out. Defaults to + :file:`registration/logged_out.html` if no argument is supplied. + + * ``redirect_field_name``: The name of a ``GET`` field containing the + URL to redirect to after log out. Overrides ``next_page`` if the given + ``GET`` parameter is passed. + + **Template context:** + + * ``title``: The string "Logged out", localized. + + * ``site``: The current :class:`~django.contrib.sites.models.Site`, + according to the :setting:`SITE_ID` setting. If you don't have the + site framework installed, this will be set to an instance of + :class:`~django.contrib.sites.models.RequestSite`, which derives the + site name and domain from the current + :class:`~django.http.HttpRequest`. + + * ``site_name``: An alias for ``site.name``. If you don't have the site + framework installed, this will be set to the value of + :attr:`request.META['SERVER_NAME'] `. + For more on sites, see :doc:`/ref/contrib/sites`. + +.. function:: logout_then_login(request[, login_url]) + + Logs a user out, then redirects to the login page. + + **URL name:** No default URL provided + + **Optional arguments:** + + * ``login_url``: The URL of the login page to redirect to. + Defaults to :setting:`settings.LOGIN_URL ` if not supplied. + +.. function:: password_change(request[, template_name, post_change_redirect, password_change_form]) + + Allows a user to change their password. + + **URL name:** ``password_change`` + + **Optional arguments:** + + * ``template_name``: The full name of a template to use for + displaying the password change form. Defaults to + :file:`registration/password_change_form.html` if not supplied. + + * ``post_change_redirect``: The URL to redirect to after a successful + password change. + + * ``password_change_form``: A custom "change password" form which must + accept a ``user`` keyword argument. The form is responsible for + actually changing the user's password. Defaults to + :class:`~django.contrib.auth.forms.PasswordChangeForm`. + + **Template context:** + + * ``form``: The password change form (see ``password_change_form`` above). + +.. function:: password_change_done(request[, template_name]) + + The page shown after a user has changed their password. + + **URL name:** ``password_change_done`` + + **Optional arguments:** + + * ``template_name``: The full name of a template to use. + Defaults to :file:`registration/password_change_done.html` if not + supplied. + +.. function:: password_reset(request[, is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect, from_email]) + + Allows a user to reset their password by generating a one-time use link + that can be used to reset the password, and sending that link to the + user's registered email address. + + .. versionchanged:: 1.4 + Users flagged with an unusable password (see + :meth:`~django.contrib.auth.models.User.set_unusable_password()` + will not be able to request a password reset to prevent misuse + when using an external authentication source like LDAP. + + **URL name:** ``password_reset`` + + **Optional arguments:** + + * ``template_name``: The full name of a template to use for + displaying the password reset form. Defaults to + :file:`registration/password_reset_form.html` if not supplied. + + * ``email_template_name``: The full name of a template to use for + generating the email with the reset password link. Defaults to + :file:`registration/password_reset_email.html` if not supplied. + + * ``subject_template_name``: The full name of a template to use for + the subject of the email with the reset password link. Defaults + to :file:`registration/password_reset_subject.txt` if not supplied. + + .. versionadded:: 1.4 + + * ``password_reset_form``: Form that will be used to get the email of + the user to reset the password for. Defaults to + :class:`~django.contrib.auth.forms.PasswordResetForm`. + + * ``token_generator``: Instance of the class to check the one time link. + This will default to ``default_token_generator``, it's an instance of + ``django.contrib.auth.tokens.PasswordResetTokenGenerator``. + + * ``post_reset_redirect``: The URL to redirect to after a successful + password reset request. + + * ``from_email``: A valid email address. By default Django uses + the :setting:`DEFAULT_FROM_EMAIL`. + + **Template context:** + + * ``form``: The form (see ``password_reset_form`` above) for resetting + the user's password. + + **Email template context:** + + * ``email``: An alias for ``user.email`` + + * ``user``: The current :class:`~django.contrib.auth.models.User`, + according to the ``email`` form field. Only active users are able to + reset their passwords (``User.is_active is True``). + + * ``site_name``: An alias for ``site.name``. If you don't have the site + framework installed, this will be set to the value of + :attr:`request.META['SERVER_NAME'] `. + For more on sites, see :doc:`/ref/contrib/sites`. + + * ``domain``: An alias for ``site.domain``. If you don't have the site + framework installed, this will be set to the value of + ``request.get_host()``. + + * ``protocol``: http or https + + * ``uid``: The user's id encoded in base 36. + + * ``token``: Token to check that the reset link is valid. + + Sample ``registration/password_reset_email.html`` (email body template): + + .. code-block:: html+django + + Someone asked for password reset for email {{ email }}. Follow the link below: + {{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb36=uid token=token %} + + The same template context is used for subject template. Subject must be + single line plain text string. + + +.. function:: password_reset_done(request[, template_name]) + + The page shown after a user has been emailed a link to reset their + password. This view is called by default if the :func:`password_reset` view + doesn't have an explicit ``post_reset_redirect`` URL set. + + **URL name:** ``password_reset_done`` + + **Optional arguments:** + + * ``template_name``: The full name of a template to use. + Defaults to :file:`registration/password_reset_done.html` if not + supplied. + +.. function:: password_reset_confirm(request[, uidb36, token, template_name, token_generator, set_password_form, post_reset_redirect]) + + Presents a form for entering a new password. + + **URL name:** ``password_reset_confirm`` + + **Optional arguments:** + + * ``uidb36``: The user's id encoded in base 36. Defaults to ``None``. + + * ``token``: Token to check that the password is valid. Defaults to + ``None``. + + * ``template_name``: The full name of a template to display the confirm + password view. Default value is :file:`registration/password_reset_confirm.html`. + + * ``token_generator``: Instance of the class to check the password. This + will default to ``default_token_generator``, it's an instance of + ``django.contrib.auth.tokens.PasswordResetTokenGenerator``. + + * ``set_password_form``: Form that will be used to set the password. + Defaults to :class:`~django.contrib.auth.forms.SetPasswordForm` + + * ``post_reset_redirect``: URL to redirect after the password reset + done. Defaults to ``None``. + + **Template context:** + + * ``form``: The form (see ``set_password_form`` above) for setting the + new user's password. + + * ``validlink``: Boolean, True if the link (combination of uidb36 and + token) is valid or unused yet. + +.. function:: password_reset_complete(request[,template_name]) + + Presents a view which informs the user that the password has been + successfully changed. + + **URL name:** ``password_reset_complete`` + + **Optional arguments:** + + * ``template_name``: The full name of a template to display the view. + Defaults to :file:`registration/password_reset_complete.html`. + +Helper functions +---------------- + +.. currentmodule:: django.contrib.auth.views + +.. function:: redirect_to_login(next[, login_url, redirect_field_name]) + + Redirects to the login page, and then back to another URL after a + successful login. + + **Required arguments:** + + * ``next``: The URL to redirect to after a successful login. + + **Optional arguments:** + + * ``login_url``: The URL of the login page to redirect to. + Defaults to :setting:`settings.LOGIN_URL ` if not supplied. + + * ``redirect_field_name``: The name of a ``GET`` field containing the + URL to redirect to after log out. Overrides ``next`` if the given + ``GET`` parameter is passed. + + +.. _built-in-auth-forms: + +Built-in forms +-------------- + +.. module:: django.contrib.auth.forms + +If you don't want to use the built-in views, but want the convenience of not +having to write forms for this functionality, the authentication system +provides several built-in forms located in :mod:`django.contrib.auth.forms`: + +.. class:: AdminPasswordChangeForm + + A form used in the admin interface to change a user's password. + +.. class:: AuthenticationForm + + A form for logging a user in. + +.. class:: PasswordChangeForm + + A form for allowing a user to change their password. + +.. class:: PasswordResetForm + + A form for generating and emailing a one-time use link to reset a + user's password. + +.. class:: SetPasswordForm + + A form that lets a user change his/her password without entering the old + password. + +.. class:: UserChangeForm + + A form used in the admin interface to change a user's information and + permissions. + +.. class:: UserCreationForm + + A form for creating a new user. + +.. currentmodule:: django.contrib.auth + + +Authentication data in templates +-------------------------------- + +The currently logged-in user and his/her permissions are made available in the +:doc:`template context ` when you use +:class:`~django.template.RequestContext`. + +.. admonition:: Technicality + + Technically, these variables are only made available in the template context + if you use :class:`~django.template.RequestContext` *and* your + :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting contains + ``"django.contrib.auth.context_processors.auth"``, which is default. For + more, see the :ref:`RequestContext docs `. + +Users +~~~~~ + +When rendering a template :class:`~django.template.RequestContext`, the +currently logged-in user, either a :class:`~django.contrib.auth.models.User` +instance or an :class:`~django.contrib.auth.models.AnonymousUser` instance, is +stored in the template variable ``{{ user }}``: + +.. code-block:: html+django + + {% if user.is_authenticated %} +

Welcome, {{ user.username }}. Thanks for logging in.

+ {% else %} +

Welcome, new user. Please log in.

+ {% endif %} + +This template context variable is not available if a ``RequestContext`` is not +being used. + +Permissions +~~~~~~~~~~~ + +The currently logged-in user's permissions are stored in the template variable +``{{ perms }}``. This is an instance of +``django.contrib.auth.context_processors.PermWrapper``, which is a +template-friendly proxy of permissions. + +In the ``{{ perms }}`` object, single-attribute lookup is a proxy to +:meth:`User.has_module_perms `. +This example would display ``True`` if the logged-in user had any permissions +in the ``foo`` app:: + + {{ perms.foo }} + +Two-level-attribute lookup is a proxy to +:meth:`User.has_perm `. This example +would display ``True`` if the logged-in user had the permission +``foo.can_vote``:: + + {{ perms.foo.can_vote }} + +Thus, you can check permissions in template ``{% if %}`` statements: + +.. code-block:: html+django + + {% if perms.foo %} +

You have permission to do something in the foo app.

+ {% if perms.foo.can_vote %} +

You can vote!

+ {% endif %} + {% if perms.foo.can_drive %} +

You can drive!

+ {% endif %} + {% else %} +

You don't have permission to do anything in the foo app.

+ {% endif %} + +.. versionadded:: 1.5 + Permission lookup by "if in". + +It is possible to also look permissions up by ``{% if in %}`` statements. +For example: + +.. code-block:: html+django + + {% if 'foo' in perms %} + {% if 'foo.can_vote' in perms %} +

In lookup works, too.

+ {% endif %} + {% endif %} + +.. _auth-admin: + +Managing users in the admin +=========================== + +When you have both ``django.contrib.admin`` and ``django.contrib.auth`` +installed, the admin provides a convenient way to view and manage users, +groups, and permissions. Users can be created and deleted like any Django +model. Groups can be created, and permissions can be assigned to users or +groups. A log of user edits to models made within the admin is also stored and +displayed. + +Creating Users +-------------- + +You should see a link to "Users" in the "Auth" +section of the main admin index page. The "Add user" admin page is different +than standard admin pages in that it requires you to choose a username and +password before allowing you to edit the rest of the user's fields. + +Also note: if you want a user account to be able to create users using the +Django admin site, you'll need to give them permission to add users *and* +change users (i.e., the "Add user" and "Change user" permissions). If an +account has permission to add users but not to change them, that account won't +be able to add users. Why? Because if you have permission to add users, you +have the power to create superusers, which can then, in turn, change other +users. So Django requires add *and* change permissions as a slight security +measure. + +Changing Passwords +------------------ + +User passwords are not displayed in the admin (nor stored in the database), but +the :doc:`password storage details ` are displayed. +Included in the display of this information is a link to +a password change form that allows admins to change user passwords. diff --git a/docs/topics/auth/index.txt b/docs/topics/auth/index.txt new file mode 100644 index 00000000000..ddb2d2f9922 --- /dev/null +++ b/docs/topics/auth/index.txt @@ -0,0 +1,81 @@ +============================= +User authentication in Django +============================= + +.. toctree:: + :hidden: + + default + passwords + customizing + +.. module:: django.contrib.auth + :synopsis: Django's authentication framework. + +Django comes with an user authentication system. It handles user accounts, +groups, permissions and cookie-based user sessions. This section of the +documentation explains how the default implementation works out of the box, as +well as how to :doc:`extend and customize ` it to +suit your project's needs. + +Overview +======== + +The Django authentication system handles both authentication and authorization. +Briefly, authentication verifies a user is who they claim to be, and +authorization determines what an authenticated user is allowed to do. Here the +term authentication is used to refer to both tasks. + +The auth system consists of: + +* Users +* Permissions: Binary (yes/no) flags designating whether a user may perform + a certain task. +* Groups: A generic way of applying labels and permissions to more than one + user. +* A configurable password hashing system +* Forms and view tools for logging in users, or restricting content +* A pluggable backend system + +Installation +============ + +Authentication support is bundled as a Django contrib module in +``django.contrib.auth``. By default, the required configuration is already +included in the :file:`settings.py` generated by :djadmin:`django-admin.py +startproject `, these consist of two items listed in your +:setting:`INSTALLED_APPS` setting: + +1. ``'django.contrib.auth'`` contains the core of the authentication framework, + and its default models. +2. ``'django.contrib.contenttypes'`` is the Django :doc:`content type system + `, which allows permissions to be associated with + models you create. + +and two items in your :setting:`MIDDLEWARE_CLASSES` setting: + +1. :class:`~django.contrib.sessions.middleware.SessionMiddleware` manages + :doc:`sessions ` across requests. +2. :class:`~django.contrib.auth.middleware.AuthenticationMiddleware` associates + users with requests using sessions. + +With these settings in place, running the command ``manage.py syncdb`` creates +the necessary database tables for auth related models, creates permissions for +any models defined in your installed apps, and prompts you to create +a superuser account the first time you run it. + +Usage +===== + +:doc:`Using Django's default implementation ` + +* :ref:`Working with User objects ` +* :ref:`Permissions and authorization ` +* :ref:`Authentication in web requests ` +* :ref:`Managing users in the admin ` + +:doc:`API reference for the default implementation ` + +:doc:`Customizing Users and authentication ` + +:doc:`Password management in Django ` diff --git a/docs/topics/auth/passwords.txt b/docs/topics/auth/passwords.txt new file mode 100644 index 00000000000..e6345aab2ea --- /dev/null +++ b/docs/topics/auth/passwords.txt @@ -0,0 +1,212 @@ +============================= +Password management in Django +============================= + +Password management is something that should generally not be reinvented +unnecessarily, and Django endeavors to provide a secure and flexible set of +tools for managing user passwords. This document describes how Django stores +passwords, how the storage hashing can be configured, and some utilities to +work with hashed passwords. + +.. _auth_password_storage: + +How Django stores passwords +=========================== + +.. versionadded:: 1.4 + Django 1.4 introduces a new flexible password storage system and uses + PBKDF2 by default. Previous versions of Django used SHA1, and other + algorithms couldn't be chosen. + +The :attr:`~django.contrib.auth.models.User.password` attribute of a +:class:`~django.contrib.auth.models.User` object is a string in this format:: + + algorithm$hash + +That's a storage algorithm, and hash, separated by the dollar-sign +character. The algorithm is one of a number of one way hashing or password +storage algorithms Django can use; see below. The hash is the result of the one- +way function. + +By default, Django uses the PBKDF2_ algorithm with a SHA256 hash, a +password stretching mechanism recommended by NIST_. This should be +sufficient for most users: it's quite secure, requiring massive +amounts of computing time to break. + +However, depending on your requirements, you may choose a different +algorithm, or even use a custom algorithm to match your specific +security situation. Again, most users shouldn't need to do this -- if +you're not sure, you probably don't. If you do, please read on: + +Django chooses the an algorithm by consulting the :setting:`PASSWORD_HASHERS` +setting. This is a list of hashing algorithm classes that this Django +installation supports. The first entry in this list (that is, +``settings.PASSWORD_HASHERS[0]``) will be used to store passwords, and all the +other entries are valid hashers that can be used to check existing passwords. +This means that if you want to use a different algorithm, you'll need to modify +:setting:`PASSWORD_HASHERS` to list your preferred algorithm first in the list. + +The default for :setting:`PASSWORD_HASHERS` is:: + + PASSWORD_HASHERS = ( + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', + 'django.contrib.auth.hashers.BCryptPasswordHasher', + 'django.contrib.auth.hashers.SHA1PasswordHasher', + 'django.contrib.auth.hashers.MD5PasswordHasher', + 'django.contrib.auth.hashers.CryptPasswordHasher', + ) + +This means that Django will use PBKDF2_ to store all passwords, but will support +checking passwords stored with PBKDF2SHA1, bcrypt_, SHA1_, etc. The next few +sections describe a couple of common ways advanced users may want to modify this +setting. + +.. _bcrypt_usage: + +Using bcrypt with Django +------------------------ + +Bcrypt_ is a popular password storage algorithm that's specifically designed +for long-term password storage. It's not the default used by Django since it +requires the use of third-party libraries, but since many people may want to +use it Django supports bcrypt with minimal effort. + +To use Bcrypt as your default storage algorithm, do the following: + +1. Install the `py-bcrypt`_ library (probably by running ``sudo pip install + py-bcrypt``, or downloading the library and installing it with ``python + setup.py install``). + +2. Modify :setting:`PASSWORD_HASHERS` to list ``BCryptPasswordHasher`` + first. That is, in your settings file, you'd put:: + + PASSWORD_HASHERS = ( + 'django.contrib.auth.hashers.BCryptPasswordHasher', + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', + 'django.contrib.auth.hashers.SHA1PasswordHasher', + 'django.contrib.auth.hashers.MD5PasswordHasher', + 'django.contrib.auth.hashers.CryptPasswordHasher', + ) + + (You need to keep the other entries in this list, or else Django won't + be able to upgrade passwords; see below). + +That's it -- now your Django install will use Bcrypt as the default storage +algorithm. + +.. admonition:: Other bcrypt implementations + + There are several other implementations that allow bcrypt to be + used with Django. Django's bcrypt support is NOT directly + compatible with these. To upgrade, you will need to modify the + hashes in your database to be in the form `bcrypt$(raw bcrypt + output)`. For example: + `bcrypt$$2a$12$NT0I31Sa7ihGEWpka9ASYrEFkhuTNeBQ2xfZskIiiJeyFXhRgS.Sy`. + +Increasing the work factor +-------------------------- + +The PBKDF2 and bcrypt algorithms use a number of iterations or rounds of +hashing. This deliberately slows down attackers, making attacks against hashed +passwords harder. However, as computing power increases, the number of +iterations needs to be increased. We've chosen a reasonable default (and will +increase it with each release of Django), but you may wish to tune it up or +down, depending on your security needs and available processing power. To do so, +you'll subclass the appropriate algorithm and override the ``iterations`` +parameters. For example, to increase the number of iterations used by the +default PBKDF2 algorithm: + +1. Create a subclass of ``django.contrib.auth.hashers.PBKDF2PasswordHasher``:: + + from django.contrib.auth.hashers import PBKDF2PasswordHasher + + class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher): + """ + A subclass of PBKDF2PasswordHasher that uses 100 times more iterations. + """ + iterations = PBKDF2PasswordHasher.iterations * 100 + + Save this somewhere in your project. For example, you might put this in + a file like ``myproject/hashers.py``. + +2. Add your new hasher as the first entry in :setting:`PASSWORD_HASHERS`:: + + PASSWORD_HASHERS = ( + 'myproject.hashers.MyPBKDF2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', + 'django.contrib.auth.hashers.BCryptPasswordHasher', + 'django.contrib.auth.hashers.SHA1PasswordHasher', + 'django.contrib.auth.hashers.MD5PasswordHasher', + 'django.contrib.auth.hashers.CryptPasswordHasher', + ) + + +That's it -- now your Django install will use more iterations when it +stores passwords using PBKDF2. + +Password upgrading +------------------ + +When users log in, if their passwords are stored with anything other than +the preferred algorithm, Django will automatically upgrade the algorithm +to the preferred one. This means that old installs of Django will get +automatically more secure as users log in, and it also means that you +can switch to new (and better) storage algorithms as they get invented. + +However, Django can only upgrade passwords that use algorithms mentioned in +:setting:`PASSWORD_HASHERS`, so as you upgrade to new systems you should make +sure never to *remove* entries from this list. If you do, users using un- +mentioned algorithms won't be able to upgrade. + +.. _sha1: http://en.wikipedia.org/wiki/SHA1 +.. _pbkdf2: http://en.wikipedia.org/wiki/PBKDF2 +.. _nist: http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf +.. _bcrypt: http://en.wikipedia.org/wiki/Bcrypt +.. _py-bcrypt: http://pypi.python.org/pypi/py-bcrypt/ + + +Manually managing a user's password +=================================== + +.. module:: django.contrib.auth.hashers + +.. versionadded:: 1.4 + The :mod:`django.contrib.auth.hashers` module provides a set of functions + to create and validate hashed password. You can use them independently + from the ``User`` model. + +.. function:: check_password(password, encoded) + + .. versionadded:: 1.4 + + If you'd like to manually authenticate a user by comparing a plain-text + password to the hashed password in the database, use the convenience + function :func:`django.contrib.auth.hashers.check_password`. It takes two + arguments: the plain-text password to check, and the full value of a + user's ``password`` field in the database to check against, and returns + ``True`` if they match, ``False`` otherwise. + +.. function:: make_password(password[, salt, hashers]) + + .. versionadded:: 1.4 + + Creates a hashed password in the format used by this application. It takes + one mandatory argument: the password in plain-text. Optionally, you can + provide a salt and a hashing algorithm to use, if you don't want to use the + defaults (first entry of ``PASSWORD_HASHERS`` setting). + Currently supported algorithms are: ``'pbkdf2_sha256'``, ``'pbkdf2_sha1'``, + ``'bcrypt'`` (see :ref:`bcrypt_usage`), ``'sha1'``, ``'md5'``, + ``'unsalted_md5'`` (only for backward compatibility) and ``'crypt'`` + if you have the ``crypt`` library installed. If the password argument is + ``None``, an unusable password is returned (a one that will be never + accepted by :func:`django.contrib.auth.hashers.check_password`). + +.. function:: is_password_usable(encoded_password) + + .. versionadded:: 1.4 + + Checks if the given string is a hashed password that has a chance + of being verified against :func:`django.contrib.auth.hashers.check_password`. diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt index cfa794ca924..c4db0d77a73 100644 --- a/docs/topics/db/models.txt +++ b/docs/topics/db/models.txt @@ -1063,52 +1063,46 @@ Proxy models are declared like normal models. You tell Django that it's a proxy model by setting the :attr:`~django.db.models.Options.proxy` attribute of the ``Meta`` class to ``True``. -For example, suppose you want to add a method to the standard -:class:`~django.contrib.auth.models.User` model that will be used in your -templates. You can do it like this:: +For example, suppose you want to add a method to the ``Person`` model described +above. You can do it like this:: - from django.contrib.auth.models import User - - class MyUser(User): + class MyPerson(Person): class Meta: proxy = True def do_something(self): ... -The ``MyUser`` class operates on the same database table as its parent -:class:`~django.contrib.auth.models.User` class. In particular, any new -instances of :class:`~django.contrib.auth.models.User` will also be accessible -through ``MyUser``, and vice-versa:: +The ``MyPerson`` class operates on the same database table as its parent +``Person`` class. In particular, any new instances of ``Person`` will also be +accessible through ``MyPerson``, and vice-versa:: - >>> u = User.objects.create(username="foobar") - >>> MyUser.objects.get(username="foobar") - + >>> p = Person.objects.create(first_name="foobar") + >>> MyPerson.objects.get(first_name="foobar") + -You could also use a proxy model to define a different default ordering on a -model. The standard :class:`~django.contrib.auth.models.User` model has no -ordering defined on it (intentionally; sorting is expensive and we don't want -to do it all the time when we fetch users). You might want to regularly order -by the ``username`` attribute when you use the proxy. This is easy:: +You could also use a proxy model to define a different default ordering on +a model. You might not always want to order the ``Person`` model, but regularly +order by the ``last_name`` attribute when you use the proxy. This is easy:: - class OrderedUser(User): + class OrderedPerson(Person): class Meta: - ordering = ["username"] + ordering = ["last_name"] proxy = True -Now normal :class:`~django.contrib.auth.models.User` queries will be unordered -and ``OrderedUser`` queries will be ordered by ``username``. +Now normal ``Person`` queries will be unordered +and ``OrderedPerson`` queries will be ordered by ``last_name``. QuerySets still return the model that was requested ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There is no way to have Django return, say, a ``MyUser`` object whenever you -query for :class:`~django.contrib.auth.models.User` objects. A queryset for -``User`` objects will return those types of objects. The whole point of proxy -objects is that code relying on the original ``User`` will use those and your -own code can use the extensions you included (that no other code is relying on -anyway). It is not a way to replace the ``User`` (or any other) model -everywhere with something of your own creation. +There is no way to have Django return, say, a ``MyPerson`` object whenever you +query for ``Person`` objects. A queryset for ``Person`` objects will return +those types of objects. The whole point of proxy objects is that code relying +on the original ``Person`` will use those and your own code can use the +extensions you included (that no other code is relying on anyway). It is not +a way to replace the ``Person`` (or any other) model everywhere with something +of your own creation. Base class restrictions ~~~~~~~~~~~~~~~~~~~~~~~ @@ -1131,12 +1125,12 @@ it will become the default, although any managers defined on the parent classes will still be available. Continuing our example from above, you could change the default manager used -when you query the ``User`` model like this:: +when you query the ``Person`` model like this:: class NewManager(models.Manager): ... - class MyUser(User): + class MyPerson(Person): objects = NewManager() class Meta: @@ -1154,7 +1148,7 @@ containing the new managers and inherit that after the primary base class:: class Meta: abstract = True - class MyUser(User, ExtraManagers): + class MyPerson(Person, ExtraManagers): class Meta: proxy = True diff --git a/docs/topics/index.txt b/docs/topics/index.txt index 82c5859b2cb..a69318f05ca 100644 --- a/docs/topics/index.txt +++ b/docs/topics/index.txt @@ -14,7 +14,7 @@ Introductions to all the key parts of Django you'll need to know: class-based-views/index files testing/index - auth + auth/index cache conditional-view-processing signing diff --git a/docs/topics/testing/overview.txt b/docs/topics/testing/overview.txt index 7b096b420d2..b748a1c7db6 100644 --- a/docs/topics/testing/overview.txt +++ b/docs/topics/testing/overview.txt @@ -651,7 +651,7 @@ Use the ``django.test.client.Client`` class to make requests. .. method:: Client.login(**credentials) - If your site uses Django's :doc:`authentication system` + If your site uses Django's :doc:`authentication system` and you deal with logging in users, you can use the test client's ``login()`` method to simulate the effect of a user logging into the site. @@ -695,7 +695,7 @@ Use the ``django.test.client.Client`` class to make requests. .. method:: Client.logout() - If your site uses Django's :doc:`authentication system`, + If your site uses Django's :doc:`authentication system`, the ``logout()`` method can be used to simulate the effect of a user logging out of your site.