diff options
| author | Jacob Kaplan-Moss <jacob@jacobian.org> | 2008-08-23 22:25:40 +0000 |
|---|---|---|
| committer | Jacob Kaplan-Moss <jacob@jacobian.org> | 2008-08-23 22:25:40 +0000 |
| commit | 97cb07c3a10ff0e584a260a7ee1001614691eb1d (patch) | |
| tree | 204f4382c51e1c288dbf547875161731661733f5 /docs/topics/auth.txt | |
| parent | b3688e81943d6d059d3f3c95095498a5aab84852 (diff) | |
Massive reorganization of the docs. See the new docs online at http://docs.djangoproject.com/.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8506 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs/topics/auth.txt')
| -rw-r--r-- | docs/topics/auth.txt | 1334 |
1 files changed, 1334 insertions, 0 deletions
diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt new file mode 100644 index 0000000000..ca73b92ea8 --- /dev/null +++ b/docs/topics/auth.txt @@ -0,0 +1,1334 @@ +.. _topics-auth: + +============================= +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. + +Installation +============ + +Authentication support is bundled as a Django application in +``django.contrib.auth``. To install it, do the following: + + 1. Put ``'django.contrib.auth'`` in your :setting:`INSTALLED_APPS` setting. + 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'`` in +:setting:`INSTALLED_APPS` for convenience. If your :setting:`INSTALLED_APPS` +already contains ``'django.contrib.auth'``, 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. Alphanumeric characters only (letters, + digits and underscores). + + .. 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 account can be used to log in. Set this + flag to ``False`` instead of deleting accounts. + + .. 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 :ref:`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() + + **New in Django development version.** + 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() + + **New in Django development version.** + Returns ``False`` if + :meth:`~django.contrib.auth.models.User.set_unusable_password()` has + been called for this user. + + .. method:: models.User.get_group_permissions() + + Returns a list of permission strings that the user has, through his/her + groups. + + .. method:: models.User.get_all_permissions() + + Returns a list of permission strings that the user has, both through group + and user permissions. + + .. method:: models.User.has_perm(perm) + + Returns ``True`` if the user has the specified permission, where perm is + in the format ``"package.codename"``. If the user is inactive, this method + will always return ``False``. + + .. method:: models.User.has_perms(perm_list) + + Returns ``True`` if the user has each of the specified permissions, where + each perm is in the format ``"package.codename"``. If the user is inactive, + this method will always return ``False``. + + .. 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`, + :attr:`~django.contrib.auth.models.User.email` and + :attr:`~django.contrib.auth.models.User.password` are set as given, and the + :class:`~django.contrib.auth.models.User` gets ``is_active=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 ``1``, + ``I`` and ``0``). + +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() + +Changing passwords +~~~~~~~~~~~~~~~~~~ + +Change a password with :meth:`~django.contrib.auth.models.User.set_password()`:: + + >>> 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, and ``crypt`` support is only available in the Django development +version. + +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.has_perm()` always returns ``False``. + * :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. + +Creating superusers +------------------- + +: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. + +**New in Django development version.**:: + + 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.ForeignKey` from your model to the +:class:`~django.contrib.auth.models.User` model, specified with ``unique=True`` +to 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 (normalized to lower-case) name of the application in which the + user profile model is defined (in other words, an all-lowercase + version of the name which was passed to + :djadmin:`manage.py startapp <startapp>` to create the application). + +2. The (normalized to lower-case) name of the model 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`. + +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 :ref:`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 +-------------------- + +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. + + **New in Django development version:** 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() + + As a shortcut, you can use the convenient + :func:`~django.contrib.auth.decorators.login_required` decorator:: + + from django.contrib.auth.decorators import login_required + + def my_view(request): + # ... + my_view = login_required(my_view) + + Here's an equivalent example, using the more compact decorator syntax + introduced in Python 2.4:: + + from django.contrib.auth.decorators import login_required + + @login_required + def my_view(request): + # ... + + In the Django development version, + :func:`~django.contrib.auth.decorators.login_required` also takes an + optional ``redirect_field_name`` parameter. Example:: + + from django.contrib.auth.decorators import login_required + + def my_view(request): + # ... + my_view = login_required(redirect_field_name='redirect_to')(my_view) + + Again, an equivalent example of the more compact decorator syntax + introduced in Python 2.4:: + + from django.contrib.auth.decorators import login_required + + @login_required(redirect_field_name='redirect_to') + 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>` (``/accounts/login/`` by + default), passing the current absolute URL in the query string as + ``next`` or the value of ``redirect_field_name``. For 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. + +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() + + 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 three + template context variables: + + * ``form``: A :class:`~django.forms.Form` object representing the + login form. See the :ref:`forms documentation <topics-forms-index>` + for more on ``FormWrapper`` objects. + + * ``next``: The URL to redirect to after successful login. This may contain + a query string, too. + + * ``site_name``: The name of the current + :class:`~django.contrib.sites.models.Site``, according to the + :setting:`SITE_ID` setting. If you're using the Django development version + and you don't have the site framework installed, this will be set to the + value of ``request.META['SERVER_NAME']``. For more on sites, see + :ref:`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'}), + + 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:: + + {% 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="."> + <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 %} + + .. _forms documentation: ../forms/ + .. _site framework docs: ../sites/ + +Other built-in views +-------------------- + +In addition to the ``login`` view, the authentication system includes a +few other useful built-in views: + +.. function:: django.contrib.auth.views.logout + + Logs a user out. + + **Optional arguments:** + + * ``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. + + **Template context:** + + * ``title``: The string "Logged out", localized. + +.. function:: django.contrib.auth.views.logout_then_login + + 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:: django.contrib.auth.views.password_change + + 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. + + **Template context:** + + * ``form``: The password change form. + +.. function:: django.contrib.auth.views.password_change_done + + 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:: django.contrib.auth.views.password_reset + + Allows a user to reset their password, and sends them the new password + in an e-mail. + + **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. + + **Template context:** + + * ``form``: The form for resetting the user's password. + +.. function:: django.contrib.auth.views.password_reset_done + + 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:: django.contrib.auth.views.redirect_to_login + + 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. + +Built-in 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: + + * :class:`django.contrib.auth.forms.AdminPasswordChangeForm`: A form used + in the admin interface to change a user's password. + + * :class:`django.contrib.auth.forms.AuthenticationForm`: A form for + logging a user in. + + * :class:`django.contrib.auth.forms.PasswordChangeForm`: A form for + allowing a user to change their password. + + * :class:`django.contrib.auth.forms.PasswordResetForm`: A form for + resetting a user's password and e-mailing the new password to them. + + * :class:`django.contrib.auth.forms.UserCreationForm`: A form for creating + a new 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 <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.is_authenticated() and 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 + + def my_view(request): + # ... + my_view = user_passes_test(lambda u: u.has_perm('polls.can_vote'))(my_view) + + 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. + + Here's the same thing, using Python 2.4's decorator syntax:: + + from django.contrib.auth.decorators import user_passes_test + + @user_passes_test(lambda u: u.has_perm('polls.can_vote')) + 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 <LOGIN_URL>` by default). + + Example in Python 2.3 syntax:: + + from django.contrib.auth.decorators import user_passes_test + + def my_view(request): + # ... + my_view = user_passes_test(lambda u: u.has_perm('polls.can_vote'), login_url='/login/')(my_view) + + Example in Python 2.4 syntax:: + + 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 + + def my_view(request): + # ... + my_view = permission_required('polls.can_vote')(my_view) + + 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 + + def my_view(request): + # ... + my_view = permission_required('polls.can_vote', login_url='/loginpage/')(my_view) + + As in the ``login_required`` decorator, ``login_url`` defaults to + :setting:`settings.LOGIN_URL <LOGIN_URL>`. + +Limiting access to generic views +-------------------------------- + +To limit access to a :ref:`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 +=========== + +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>`. + +.. _custom-permissions: + +Custom permissions +------------------ + +To create custom permissions for a given model object, use the ``permissions`` +:ref:`model Meta attribute <meta-options>`. + +This example model creates three custom permissions:: + + class USCitizen(models.Model): + # ... + class Meta: + permissions = ( + ("can_drive", "Can drive"), + ("can_vote", "Can vote in elections"), + ("can_drink", "Can drink alcohol"), + ) + +The only thing this does is create those extra permissions when you run +:djadmin:`manage.py syncdb <syncdb>`. + +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 :ref:`Django model <ref-models-instances>`. + +Authentication data in templates +================================ + +The currently logged-in user and his/her permissions are made available in the +:ref:`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.core.context_processors.auth"``, which is default. For more, see + the :ref:`RequestContext docs <subclassing-context-requestcontext>`. + +Users +----- + +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 }}``:: + + {% if user.is_authenticated %} + <p>Welcome, {{ user.username }}. Thanks for logging in.</p> + {% else %} + <p>Welcome, new user. Please log in.</p> + {% endif %} + +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:: + + {% 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 +======== + +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 +:ref:`template context <ref-templates-api>` as the template variable +``{{ messages }}``. Here's an example of template code that displays messages:: + + {% if messages %} + <ul> + {% for message in messages %} + <li>{{ message }}</li> + {% endfor %} + </ul> + {% endif %} + +Note that :class:`~django.template.context.RequestContext` calls +:meth:`~django.contrib.auth.models.User.get_and_delete_messages` behind the +scenes, so any messages will be deleted even if you don't display them. + +Finally, note that this messages framework only works with users in the user +database. To send messages to anonymous users, use the +:ref:`session framework <topics-http-sessions>`. + +.. _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 another authentication sources. You can override Django's default +database-based scheme, or you can use the default system in tandem with other +systems. + +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 "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. + +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 |
