diff options
author | Nishanth Amuluru | 2011-01-08 11:20:57 +0530 |
---|---|---|
committer | Nishanth Amuluru | 2011-01-08 11:20:57 +0530 |
commit | 65411d01d448ff0cd4abd14eee14cf60b5f8fc20 (patch) | |
tree | b4c404363c4c63a61d6e2f8bd26c5b057c1fb09d /parts/django/docs/topics/auth.txt | |
parent | 2e35094d43b4cc6974172e1febf76abb50f086ec (diff) | |
download | pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.tar.gz pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.tar.bz2 pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.zip |
Added buildout stuff and made changes accordingly
--HG--
rename : profile/management/__init__.py => eggs/djangorecipe-0.20-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/djangorecipe-0.20-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/infrae.subversion-1.4.5-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/infrae.subversion-1.4.5-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/py-1.4.0-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/py-1.4.0-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/zc.buildout-1.5.2-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/zc.buildout-1.5.2-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/zc.recipe.egg-1.3.2-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/zc.recipe.egg-1.3.2-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => parts/django/Django.egg-info/dependency_links.txt
rename : taskapp/models.py => parts/django/django/conf/app_template/models.py
rename : taskapp/tests.py => parts/django/django/conf/app_template/tests.py
rename : taskapp/views.py => parts/django/django/conf/app_template/views.py
rename : taskapp/views.py => parts/django/django/contrib/gis/tests/geo3d/views.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/delete/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/files/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/invalid_models/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/m2m_signals/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/model_package/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/management/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/management/commands/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/models.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/delete_regress/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/file_storage/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/max_lengths/__init__.py
rename : profile/forms.py => pytask/profile/forms.py
rename : profile/management/__init__.py => pytask/profile/management/__init__.py
rename : profile/management/commands/seed_db.py => pytask/profile/management/commands/seed_db.py
rename : profile/models.py => pytask/profile/models.py
rename : profile/templatetags/user_tags.py => pytask/profile/templatetags/user_tags.py
rename : taskapp/tests.py => pytask/profile/tests.py
rename : profile/urls.py => pytask/profile/urls.py
rename : profile/utils.py => pytask/profile/utils.py
rename : profile/views.py => pytask/profile/views.py
rename : static/css/base.css => pytask/static/css/base.css
rename : taskapp/tests.py => pytask/taskapp/tests.py
rename : taskapp/views.py => pytask/taskapp/views.py
rename : templates/base.html => pytask/templates/base.html
rename : templates/profile/browse_notifications.html => pytask/templates/profile/browse_notifications.html
rename : templates/profile/edit.html => pytask/templates/profile/edit.html
rename : templates/profile/view.html => pytask/templates/profile/view.html
rename : templates/profile/view_notification.html => pytask/templates/profile/view_notification.html
rename : templates/registration/activate.html => pytask/templates/registration/activate.html
rename : templates/registration/activation_email.txt => pytask/templates/registration/activation_email.txt
rename : templates/registration/activation_email_subject.txt => pytask/templates/registration/activation_email_subject.txt
rename : templates/registration/logged_out.html => pytask/templates/registration/logged_out.html
rename : templates/registration/login.html => pytask/templates/registration/login.html
rename : templates/registration/logout.html => pytask/templates/registration/logout.html
rename : templates/registration/password_change_done.html => pytask/templates/registration/password_change_done.html
rename : templates/registration/password_change_form.html => pytask/templates/registration/password_change_form.html
rename : templates/registration/password_reset_complete.html => pytask/templates/registration/password_reset_complete.html
rename : templates/registration/password_reset_confirm.html => pytask/templates/registration/password_reset_confirm.html
rename : templates/registration/password_reset_done.html => pytask/templates/registration/password_reset_done.html
rename : templates/registration/password_reset_email.html => pytask/templates/registration/password_reset_email.html
rename : templates/registration/password_reset_form.html => pytask/templates/registration/password_reset_form.html
rename : templates/registration/registration_complete.html => pytask/templates/registration/registration_complete.html
rename : templates/registration/registration_form.html => pytask/templates/registration/registration_form.html
rename : utils.py => pytask/utils.py
Diffstat (limited to 'parts/django/docs/topics/auth.txt')
-rw-r--r-- | parts/django/docs/topics/auth.txt | 1612 |
1 files changed, 1612 insertions, 0 deletions
diff --git a/parts/django/docs/topics/auth.txt b/parts/django/docs/topics/auth.txt new file mode 100644 index 0000000..a58e523 --- /dev/null +++ b/parts/django/docs/topics/auth.txt @@ -0,0 +1,1612 @@ +============================= +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. + * Messages: A simple way to queue messages for given users. + +.. deprecated:: 1.2 + The Messages component of the auth system will be removed in Django 1.4. + +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 <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 +<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. Alphanumeric characters only + (letters, digits and underscores). + + .. versionchanged:: 1.2 + Usernames may now contain ``@``, ``+``, ``.`` 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. E-mail 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, so 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. + However, the :class:`~django.contrib.auth.forms.AuthenticationForm` + used by the :func:`~django.contrib.auth.views.login` view *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: models.User. ``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 + </topics/db/models>`: + + .. 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.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() + + .. versionadded:: 1.0 + + 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() + + .. versionadded:: 1.0 + + 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. + + .. versionadded:: 1.2 + + 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. + + .. versionadded:: 1.2 + + 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 ``"<app label>.<permission codename>"``. (see + `permissions`_ section below). If the user is inactive, this method will + always return ``False``. + + .. versionadded:: 1.2 + + 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 + ``"<app label>.<permission codename>"``. If the user is inactive, + this method will always return ``False``. + + .. versionadded:: 1.2 + + 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.get_and_delete_messages() + + Returns a list of :class:`~django.contrib.auth.models.Message` objects + in the user's queue and deletes the messages from the queue. + + .. method:: models.User.email_user(subject, message, from_email=None) + + Sends an e-mail 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() + + Returns a site-specific profile for this user. Raises + :exc:`django.contrib.auth.models.SiteProfileNotAvailable` if the + current site doesn't allow profiles. 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, password=None) + + 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 convered 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 +~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.2 + The ``manage.py changepassword`` command was added. + +:djadmin:`manage.py changepassword *username* <changepassword>` 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. + +Passwords +--------- + +The :attr:`~django.contrib.auth.models.User.password` attribute of a +:class:`~django.contrib.auth.models.User` object is a string in this format:: + + hashtype$salt$hash + +That's hashtype, salt and hash, separated by the dollar-sign character. + +Hashtype is either ``sha1`` (default), ``md5`` or ``crypt`` -- the algorithm +used to perform a one-way hash of the password. Salt is a random string used +to salt the raw password to create the hash. Note that the ``crypt`` method is +only supported on platforms that have the standard Python ``crypt`` module +available. + +.. versionadded:: 1.0 + Support for the ``crypt`` module is new in Django 1.0. + +For example:: + + sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4 + +The :meth:`~django.contrib.auth.models.User.set_password` and +:meth:`~django.contrib.auth.models.User.check_password` functions handle the +setting and checking of these values behind the scenes. + +Previous Django versions, such as 0.90, used simple MD5 hashes without password +salts. For backwards compatibility, those are still supported; they'll be +converted automatically to the new style the first time +:meth:`~django.contrib.auth.models.User.check_password()` works correctly for +a given user. + +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:`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 +------------------- + +.. versionadded:: 1.0 + The ``manage.py createsuperuser`` command is new. + +:djadmin:`manage.py syncdb <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 +------------------------------------------ + +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` 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`. + +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 <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 the profile, if it does not exist. You need to +register a handler for the signal +:attr:`django.db.models.signals.post_save` on the User model, and, in +the handler, if created=True, create the associated user profile. + +For more information, see `Chapter 12 of the Django book`_. + +.. _Chapter 12 of the Django book: http://www.djangobook.com/en/1.0/chapter12/#cn222 + +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 <django.http.HttpRequest>`. + +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 </topics/http/sessions>` for more information. + +Once you have those middlewares installed, you'll be able to access +:attr:`request.user <django.http.HttpRequest.user>` in views. +:attr:`request.user <django.http.HttpRequest.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 <django.http.HttpRequest.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. + + 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 checking a user's password +----------------------------------- + +.. function:: check_password() + + 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.models.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. + +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. + + .. versionchanged:: 1.0 + Calling ``logout()`` now cleans session data. + + 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() +<django.contrib.auth.models.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]) + + 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 <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): + ... + + 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 it's key rather than ``"next"`` (the default). + + Note that you'll need to map the appropriate Django view to + :setting:`settings.LOGIN_URL <LOGIN_URL>`. For example, using the defaults, + add the following line to your URLconf:: + + (r'^accounts/login/$', 'django.contrib.auth.views.login'), + +.. function:: views.login(request, [template_name, redirect_field_name, authentication_form]) + + 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 <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 </topics/forms/index>` 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'] <django.http.HttpRequest.META>`. + 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 %} + <p>Your username and password didn't match. Please try again.</p> + {% endif %} + + <form method="post" action="{% url django.contrib.auth.views.login %}"> + {% csrf_token %} + <table> + <tr> + <td>{{ form.username.label_tag }}</td> + <td>{{ form.username }}</td> + </tr> + <tr> + <td>{{ form.password.label_tag }}</td> + <td>{{ form.password }}</td> + </tr> + </table> + + <input type="submit" value="login" /> + <input type="hidden" name="next" value="{{ next }}" /> + </form> + + {% endblock %} + + .. versionadded:: 1.2 + + 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/ + +Other built-in 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:: views.logout(request, [next_page, template_name, redirect_field_name]) + + Logs a user out. + + **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. This will default 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. + +.. function:: views.logout_then_login(request[, login_url]) + + Logs a user out, then redirects to the login page. + + **Optional arguments:** + + * ``login_url``: The URL of the login page to redirect to. This will + default to :setting:`settings.LOGIN_URL <LOGIN_URL>` if not supplied. + +.. function:: views.password_change(request[, template_name, post_change_redirect, password_change_form]) + + Allows a user to change their password. + + **Optional arguments:** + + * ``template_name``: The full name of a template to use for + displaying the password change form. This will default to + :file:`registration/password_change_form.html` if not supplied. + + * ``post_change_redirect``: The URL to redirect to after a successful + password change. + + * .. versionadded:: 1.2 + + ``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. + + + **Template context:** + + * ``form``: The password change form. + +.. function:: views.password_change_done(request[, template_name]) + + The page shown after a user has changed their password. + + **Optional arguments:** + + * ``template_name``: The full name of a template to use. This will + default to :file:`registration/password_change_done.html` if not + supplied. + +.. function:: views.password_reset(request[, is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect]) + + 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 e-mail address. + + **Optional arguments:** + + * ``template_name``: The full name of a template to use for + displaying the password reset form. This will default to + :file:`registration/password_reset_form.html` if not supplied. + + * ``email_template_name``: The full name of a template to use for + generating the e-mail with the new password. This will default to + :file:`registration/password_reset_email.html` if not supplied. + + * ``password_reset_form``: Form that will be used to set the password. + Defaults to :class:`~django.contrib.auth.forms.PasswordResetForm`. + + * ``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``. + + * ``post_reset_redirect``: The URL to redirect to after a successful + password change. + + **Template context:** + + * ``form``: The form for resetting the user's password. + +.. function:: views.password_reset_done(request[, template_name]) + + The page shown after a user has reset their password. + + **Optional arguments:** + + * ``template_name``: The full name of a template to use. This will + default to :file:`registration/password_reset_done.html` if not + supplied. + +.. function:: views.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. This will + default to :setting:`settings.LOGIN_URL <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. + +.. 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. + + **Optional arguments:** + + * ``uidb36``: The user's id encoded in base 36. This will default to + ``None``. + * ``token``: Token to check that the password is valid. This will default 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. + This will default to ``SetPasswordForm``. + * ``post_reset_redirect``: URL to redirect after the password reset + done. This will default to ``None``. + +.. function:: password_reset_complete(request[,template_name]) + + Presents a view which informs the user that the password has been + successfully changed. + + **Optional arguments:** + + * ``template_name``: The full name of a template to display the view. + This will default to :file:`registration/password_reset_complete.html`. + +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 e-mailing 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 + +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 +<django.http.HttpRequest.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:: decorators.user_passes_test() + + 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 <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:: decorators.permission_required() + + 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 + ``"<app label>.<permission codename>"`` (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 <LOGIN_URL>`. + +Limiting access to generic views +-------------------------------- + +To limit access to a :doc:`generic view </ref/generic-views>`, write a thin +wrapper around the view, and point your URLconf to your wrapper instead of the +generic view itself. For example:: + + from django.views.generic.date_based import object_detail + + @login_required + def limited_object_detail(*args, **kwargs): + return object_detail(*args, **kwargs) + +.. _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 are set globally per type of object, not per specific object +instance. For example, it's possible to say "Mary may change news stories," but +it's not currently possible to say "Mary may change news stories, but only the +ones she created herself" or "Mary may only change news stories that have a +certain status, publication date or ID." The latter functionality is something +Django developers are currently discussing. + +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 +<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 +<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 <meta-options>`. + +This example Task model creates three custom permissions, i.e., actions users +can or cannot do with Task instances, specific to your appication:: + + class Task(models.Model): + ... + class Meta: + permissions = ( + ("can_view", "Can see available tasks"), + ("can_change_status", "Can change the status of tasks"), + ("can_close", "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 <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.) + +API reference +------------- + +.. class:: models.Permission + + Just like users, permissions are implemented in a Django model that lives + in `django/contrib/auth/models.py`_. + +.. _django/contrib/auth/models.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py + +Fields +~~~~~~ + +:class:`~django.contrib.auth.models.Permission` objects have the following +fields: + +.. attribute:: models.Permission.name + + Required. 50 characters or fewer. Example: ``'Can vote'``. + +.. attribute:: models.Permission.content_type + + Required. A reference to the ``django_content_type`` database table, which + contains a record for each installed Django model. + +.. attribute:: models.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 </ref/models/instances>`. + +Authentication data in templates +================================ + +The currently logged-in user and his/her permissions are made available in the +:doc:`template context </ref/templates/api>` 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 <subclassing-context-requestcontext>`. + +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 %} + <p>Welcome, {{ user.username }}. Thanks for logging in.</p> + {% else %} + <p>Welcome, new user. Please log in.</p> + {% 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.core.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 <django.contrib.auth.models.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 <django.contrib.auth.models.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 %} + <p>You have permission to do something in the foo app.</p> + {% if perms.foo.can_vote %} + <p>You can vote!</p> + {% endif %} + {% if perms.foo.can_drive %} + <p>You can drive!</p> + {% endif %} + {% else %} + <p>You don't have permission to do anything in the foo app.</p> + {% 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 e-mail +messages. + +Messages +======== + +.. deprecated:: 1.2 + This functionality will be removed in Django 1.4. You should use the + :doc:`messages framework </ref/contrib/messages>` for all new projects and + begin to update your existing code immediately. + +The message system is a lightweight way to queue messages for given users. + +A message is associated with a :class:`~django.contrib.auth.models.User`. +There's no concept of expiration or timestamps. + +Messages are used by the Django admin after successful actions. For example, +``"The poll Foo was created successfully."`` is a message. + +The API is simple: + +.. method:: models.User.message_set.create(message) + + To create a new message, use + ``user_obj.message_set.create(message='message_text')``. + + To retrieve/delete messages, use + :meth:`user_obj.get_and_delete_messages() <django.contrib.auth.models.User.get_and_delete_messages>`, + which returns a list of ``Message`` objects in the user's queue (if any) + and deletes the messages from the queue. + +In this example view, the system saves a message for the user after creating +a playlist:: + + def create_playlist(request, songs): + # Create the playlist with the given songs. + # ... + request.user.message_set.create(message="Your playlist was added successfully.") + return render_to_response("playlists/create.html", + context_instance=RequestContext(request)) + +When you use :class:`~django.template.context.RequestContext`, the currently +logged-in user and his/her messages are made available in the +:doc:`template context </ref/templates/api>` as the template variable +``{{ messages }}``. Here's an example of template code that displays messages: + +.. code-block:: html+django + + {% if messages %} + <ul> + {% for message in messages %} + <li>{{ message }}</li> + {% endfor %} + </ul> + {% endif %} + +.. versionchanged:: 1.2 + The ``messages`` template variable uses a backwards compatible method in the + :doc:`messages framework </ref/contrib/messages>` to retrieve messages from + both the user ``Message`` model and from the new framework. Unlike in + previous revisions, the messages will not be erased unless they are actually + displayed. + +Finally, note that this messages framework only works with users in the user +database. To send messages to anonymous users, use the +:doc:`messages framework </ref/contrib/messages>`. + +.. _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 </ref/authbackends>` +for information on the authentication backends included with Django. + +Specifying authentication backends +---------------------------------- + +Behind the scenes, Django maintains a list of "authentication backends" that it +checks for authentication. When somebody calls +:func:`django.contrib.auth.authenticate()` -- as described in :ref:`How to log +a user in <how-to-log-a-user-in>` 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 scheme that checks the Django users database. + +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 subsequent authentication attempts for that user. This effectively means + that authentication sources are cached, 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 methods: +``get_user(user_id)`` and ``authenticate(**credentials)``. + +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: + 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: + 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: + """ + 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 + +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: + + # ... + + def has_perm(self, user_obj, perm): + 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 the backend auth functions all take the user object as an argument, +and they also accept the same arguments given to the associated +:class:`django.contrib.auth.models.User` functions. + +A full authorization implementation can be found in +`django/contrib/auth/backends.py`_, which is the default backend and queries +the ``auth_permission`` table most of the time. + +.. _django/contrib/auth/backends.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py + +Authorization for anonymous users +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionchanged:: 1.2 + +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, it has a foundation that allows custom authentication +backends to specify authorization 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. + +To enable this in your own backend, you must set the class attribute +``supports_anonymous_user`` to ``True``. (This precaution is to maintain +compatibility with backends that assume that all user objects are actual +instances of the :class:`django.contrib.auth.models.User` class). With this +in place, :class:`django.contrib.auth.models.AnonymousUser` will delegate all +the relevant permission methods to the authentication backends. + +A nonexistent ``supports_anonymous_user`` attribute will raise a hidden +``PendingDeprecationWarning`` if used in Django 1.2. In Django 1.3, this +warning will be upgraded to a ``DeprecationWarning``, which will be displayed +loudly. Additionally ``supports_anonymous_user`` will be set to ``False``. +Django 1.4 will assume that every backend supports anonymous users being +passed to the authorization 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). + +To enable object permissions in your own +:doc:`authentication backend </ref/authbackends>` you'll just have +to allow passing an ``obj`` parameter to the permission methods and set the +``supports_object_permissions`` class attribute to ``True``. + +A nonexistent ``supports_object_permissions`` will raise a hidden +``PendingDeprecationWarning`` if used in Django 1.2. In Django 1.3, this +warning will be upgraded to a ``DeprecationWarning``, which will be displayed +loudly. Additionally ``supports_object_permissions`` will be set to ``False``. +Django 1.4 will assume that every backend supports object permissions and +won't check for the existence of ``supports_object_permissions``, which +means not supporting ``obj`` as a parameter will raise a ``TypeError``. |