| ============================= |
| User authentication in Django |
| ============================= |
| |
| 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 ``INSTALLED_APPS`` setting. |
| 2. Run the command ``manage.py syncdb``. |
| |
| Note that the default ``settings.py`` file created by |
| ``django-admin.py startproject`` includes ``'django.contrib.auth'`` in |
| ``INSTALLED_APPS`` for convenience. If your ``INSTALLED_APPS`` already contains |
| ``'django.contrib.auth'``, feel free to run ``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 ``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 |
| ===== |
| |
| Users are represented by a standard Django model, which lives in |
| `django/contrib/auth/models.py`_. |
| |
| .. _django/contrib/auth/models.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py |
| |
| API reference |
| ------------- |
| |
| Fields |
| ~~~~~~ |
| |
| ``User`` objects have the following fields: |
| |
| * ``username`` -- Required. 30 characters or fewer. Alphanumeric characters |
| only (letters, digits and underscores). |
| * ``first_name`` -- Optional. 30 characters or fewer. |
| * ``last_name`` -- Optional. 30 characters or fewer. |
| * ``email`` -- Optional. E-mail address. |
| * ``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. |
| * ``is_staff`` -- Boolean. Designates whether this user can access the |
| admin site. |
| * ``is_active`` -- Boolean. Designates whether this account can be used |
| to log in. Set this flag to ``False`` instead of deleting accounts. |
| * ``is_superuser`` -- Boolean. Designates that this user has all permissions |
| without explicitly assigning them. |
| * ``last_login`` -- A datetime of the user's last login. Is set to the |
| current date/time by default. |
| * ``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 |
| ~~~~~~~ |
| |
| ``User`` objects have two many-to-many fields: ``groups`` and |
| ``user_permissions``. ``User`` objects can access their related |
| objects in the same way as any other `Django model`_:: |
| |
| 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, ``User`` objects have the following |
| custom methods: |
| |
| * ``is_anonymous()`` -- Always returns ``False``. This is a way of |
| differentiating ``User`` and ``AnonymousUser`` objects. Generally, you |
| should prefer using ``is_authenticated()`` to this method. |
| |
| * ``is_authenticated()`` -- Always returns ``True``. This is a way to |
| tell if the user has been authenticated. This does not imply any |
| permissions, and doesn't check if the user is active - it only indicates |
| that the user has provided a valid username and password. |
| |
| * ``get_full_name()`` -- Returns the ``first_name`` plus the ``last_name``, |
| with a space in between. |
| |
| * ``set_password(raw_password)`` -- Sets the user's password to the given |
| raw string, taking care of the password hashing. Doesn't save the |
| ``User`` object. |
| |
| * ``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.) |
| |
| * ``get_group_permissions()`` -- Returns a list of permission strings that |
| the user has, through his/her groups. |
| |
| * ``get_all_permissions()`` -- Returns a list of permission strings that |
| the user has, both through group and user permissions. |
| |
| * ``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``. |
| |
| * ``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``. |
| |
| * ``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``. |
| |
| * ``get_and_delete_messages()`` -- Returns a list of ``Message`` objects in |
| the user's queue and deletes the messages from the queue. |
| |
| * ``email_user(subject, message, from_email=None)`` -- Sends an e-mail to |
| the user. If ``from_email`` is ``None``, Django uses the |
| `DEFAULT_FROM_EMAIL`_ setting. |
| |
| * ``get_profile()`` -- Returns a site-specific profile for this user. |
| Raises ``django.contrib.auth.models.SiteProfileNotAvailable`` if the current site |
| doesn't allow profiles. |
| |
| .. _Django model: ../model_api/ |
| .. _DEFAULT_FROM_EMAIL: ../settings/#default-from-email |
| |
| Manager functions |
| ~~~~~~~~~~~~~~~~~ |
| |
| The ``User`` model has a custom manager that has the following helper functions: |
| |
| * ``create_user(username, email, password)`` -- Creates, saves and returns |
| a ``User``. The ``username``, ``email`` and ``password`` are set as |
| given, and the ``User`` gets ``is_active=True``. |
| |
| See _`Creating users` for example usage. |
| |
| * ``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 ``"I"`` or letters that look like it, to avoid user |
| confusion. |
| |
| Basic usage |
| ----------- |
| |
| Creating users |
| ~~~~~~~~~~~~~~ |
| |
| The most basic way to create users is to use the ``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 ready to be 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 ``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 ``password`` attribute directly unless you know what you're |
| doing. This is explained in the next section. |
| |
| Passwords |
| --------- |
| |
| The ``password`` attribute of a ``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) or ``md5`` -- 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. |
| |
| For example:: |
| |
| sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4 |
| |
| The ``User.set_password()`` and ``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 ``check_password()`` |
| works correctly for a given user. |
| |
| Anonymous users |
| --------------- |
| |
| ``django.contrib.auth.models.AnonymousUser`` is a class that implements |
| the ``django.contrib.auth.models.User`` interface, with these differences: |
| |
| * ``id`` is always ``None``. |
| * ``is_anonymous()`` returns ``True`` instead of ``False``. |
| * ``is_authenticated()`` returns ``False`` instead of ``True``. |
| * ``has_perm()`` always returns ``False``. |
| * ``set_password()``, ``check_password()``, ``save()``, ``delete()``, |
| ``set_groups()`` and ``set_permissions()`` raise ``NotImplementedError``. |
| |
| In practice, you probably won't need to use ``AnonymousUser`` objects on your |
| own, but they're used by Web requests, as explained in the next section. |
| |
| Creating superusers |
| ------------------- |
| |
| ``manage.py syncdb`` prompts you to create a superuser the first time you run |
| it after adding ``'django.contrib.auth'`` to your ``INSTALLED_APPS``. But if |
| you need to create a superuser after that via the command line, you can use the |
| ``create_superuser.py`` utility. Just run this command:: |
| |
| python /path/to/django/contrib/auth/create_superuser.py |
| |
| Make sure to substitute ``/path/to/`` with the path to the Django codebase on |
| your filesystem. |
| |
| 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 `request objects`_. |
| |
| First, install the ``SessionMiddleware`` and ``AuthenticationMiddleware`` |
| middlewares by adding them to your ``MIDDLEWARE_CLASSES`` setting. See the |
| `session documentation`_ for more information. |
| |
| Once you have those middlewares installed, you'll be able to access |
| ``request.user`` in views. ``request.user`` will give you a ``User`` object |
| representing the currently logged-in user. If a user isn't currently logged in, |
| ``request.user`` will be set to an instance of ``AnonymousUser`` (see the |
| previous section). You can tell them apart with ``is_authenticated()``, like so:: |
| |
| if request.user.is_authenticated(): |
| # Do something for authenticated users. |
| else: |
| # Do something for anonymous users. |
| |
| .. _request objects: ../request_response/#httprequest-objects |
| .. _session documentation: ../sessions/ |
| |
| How to log a user in |
| -------------------- |
| |
| Django provides two functions in ``django.contrib.auth``: ``authenticate()`` |
| and ``login()``. |
| |
| To authenticate a given username and password, use ``authenticate()``. It |
| takes two keyword arguments, ``username`` and ``password``, and it returns |
| a ``User`` object if the password is valid for the given username. If the |
| password is invalid, ``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." |
| |
| To log a user in, in a view, use ``login()``. It takes an ``HttpRequest`` |
| object and a ``User`` object. ``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 ``authenticate()`` and ``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. |
| |
| Manually checking a user's 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 `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 |
| --------------------- |
| |
| To log out a user who has been logged in via ``django.contrib.auth.login()``, |
| use ``django.contrib.auth.logout()`` within your view. It takes an |
| ``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 ``logout()`` doesn't throw any errors if the user wasn't logged in. |
| |
| Limiting access to logged-in users |
| ---------------------------------- |
| |
| The raw way |
| ~~~~~~~~~~~ |
| |
| The simple, raw way to limit access to pages is to check |
| ``request.user.is_authenticated()`` and either redirect to a login page:: |
| |
| from django.http import HttpResponseRedirect |
| |
| def my_view(request): |
| if not request.user.is_authenticated(): |
| return HttpResponseRedirect('/login/?next=%s' % request.path) |
| # ... |
| |
| ...or display an error message:: |
| |
| def my_view(request): |
| if not request.user.is_authenticated(): |
| return render_to_response('myapp/login_error.html') |
| # ... |
| |
| The login_required decorator |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| As a shortcut, you can use the convenient ``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): |
| # ... |
| |
| ``login_required`` does the following: |
| |
| * If the user isn't logged in, redirect to ``/accounts/login/``, passing |
| the current absolute URL in the query string as ``next``. 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 ``/accounts/login/``. |
| To do this, add the following line to your URLconf:: |
| |
| (r'^accounts/login/$', 'django.contrib.auth.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 ``/accounts/profile/`` (which is |
| currently hard-coded). 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 ``FormWrapper`` object representing the login form. See the |
| `forms documentation`_ 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 ``Site``, according to the |
| ``SITE_ID`` setting. See the `site framework docs`_. |
| |
| If you'd prefer not to call the template ``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 ``myapp/login.html`` |
| instead:: |
| |
| (r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}), |
| |
| Here's a sample ``registration/login.html`` template you can use as a starting |
| point. It assumes you have a ``base.html`` template that defines a ``content`` |
| block:: |
| |
| {% extends "base.html" %} |
| |
| {% block content %} |
| |
| {% if form.has_errors %} |
| <p>Your username and password didn't match. Please try again.</p> |
| {% endif %} |
| |
| <form method="post" action="."> |
| <table> |
| <tr><td><label for="id_username">Username:</label></td><td>{{ form.username }}</td></tr> |
| <tr><td><label for="id_password">Password:</label></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: |
| |
| ``django.contrib.auth.views.logout`` |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| **Description:** |
| |
| 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 |
| ``registration/logged_out.html`` if no argument is supplied. |
| |
| **Template context:** |
| |
| * ``title``: The string "Logged out", localized. |
| |
| ``django.contrib.auth.views.logout_then_login`` |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| **Description:** |
| |
| 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 ``/accounts/login/`` if not supplied. |
| |
| ``django.contrib.auth.views.password_change`` |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| **Description:** |
| |
| 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 |
| ``registration/password_change_form.html`` if not supplied. |
| |
| **Template context:** |
| |
| * ``form``: The password change form. |
| |
| ``django.contrib.auth.views.password_change_done`` |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| **Description:** |
| |
| 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 ``registration/password_change_done.html`` if not |
| supplied. |
| |
| ``django.contrib.auth.views.password_reset`` |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| **Description:** |
| |
| Allows a user to reset their password, and sends them the new password |
| in an email. |
| |
| **Optional arguments:** |
| |
| * ``template_name``: The full name of a template to use for |
| displaying the password reset form. This will default to |
| ``registration/password_reset_form.html`` if not supplied. |
| |
| * ``email_template_name``: The full name of a template to use for |
| generating the email with the new password. This will default to |
| ``registration/password_reset_email.html`` if not supplied. |
| |
| **Template context:** |
| |
| * ``form``: The form for resetting the user's password. |
| |
| ``django.contrib.auth.views.password_reset_done`` |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| **Description:** |
| |
| 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 ``registration/password_reset_done.html`` if not |
| supplied. |
| |
| ``django.contrib.auth.views.redirect_to_login`` |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| **Description:** |
| |
| 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 ``/accounts/login/`` if not supplied. |
| |
| Built-in manipulators |
| --------------------- |
| |
| If you don't want to use the built-in views, but want the convenience |
| of not having to write manipulators for this functionality, the |
| authentication system provides several built-in manipulators: |
| |
| * ``django.contrib.auth.forms.AdminPasswordChangeForm``: A |
| manipulator used in the admin interface to change a user's |
| password. |
| |
| * ``django.contrib.auth.forms.AuthenticationForm``: A manipulator |
| for logging a user in. |
| |
| * ``django.contrib.auth.forms.PasswordChangeForm``: A manipulator |
| for allowing a user to change their password. |
| |
| * ``django.contrib.auth.forms.PasswordResetForm``: A manipulator |
| for resetting a user's password and emailing the new password to |
| them. |
| |
| * ``django.contrib.auth.forms.UserCreationForm``: A manipulator |
| 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 ``request.user`` in the view directly. |
| For example, this view checks to make sure the user is logged in and has the |
| permission ``polls.can_vote``:: |
| |
| def my_view(request): |
| if not (request.user.is_authenticated() and request.user.has_perm('polls.can_vote')): |
| return HttpResponse("You can't vote in this poll.") |
| # ... |
| |
| 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 ``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): |
| # ... |
| |
| ``user_passes_test`` takes a required argument: a callable that takes a |
| ``User`` object and returns ``True`` if the user is allowed to view the page. |
| Note that ``user_passes_test`` does not automatically check that the ``User`` |
| is not anonymous. |
| |
| ``user_passes_test()`` takes an optional ``login_url`` argument, which lets you |
| specify the URL for your login page (``/accounts/login/`` 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 |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| **New in Django development version** |
| |
| 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 |
| ``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 ``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 |
| ``'/accounts/login/'``. |
| |
| Limiting access to generic views |
| -------------------------------- |
| |
| To limit access to a `generic view`_, 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) |
| |
| .. _generic view: ../generic_views/ |
| |
| 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 |
| ------------------- |
| |
| Three basic permissions -- add, create and delete -- are automatically created |
| for each Django model that has a ``class Admin`` set. Behind the scenes, these |
| permissions are added to the ``auth_permission`` database table when you run |
| ``manage.py syncdb``. |
| |
| Note that if your model doesn't have ``class Admin`` set when you run |
| ``syncdb``, the permissions won't be created. If you initialize your database |
| and add ``class Admin`` to models after the fact, you'll need to run |
| ``manage.py syncdb`` again. It will create any missing permissions for |
| all of your installed apps. |
| |
| Custom permissions |
| ------------------ |
| |
| To create custom permissions for a given model object, use the ``permissions`` |
| `model Meta attribute`_. |
| |
| 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 |
| ``syncdb``. |
| |
| .. _model Meta attribute: ../model_api/#meta-options |
| |
| API reference |
| ------------- |
| |
| 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 |
| ~~~~~~ |
| |
| ``Permission`` objects have the following fields: |
| |
| * ``name`` -- Required. 50 characters or fewer. Example: ``'Can vote'``. |
| * ``content_type`` -- Required. A reference to the ``django_content_type`` |
| database table, which contains a record for each installed Django model. |
| * ``codename`` -- Required. 100 characters or fewer. Example: ``'can_vote'``. |
| |
| Methods |
| ~~~~~~~ |
| |
| ``Permission`` objects have the standard data-access methods like any other |
| `Django model`_. |
| |
| Authentication data in templates |
| ================================ |
| |
| The currently logged-in user and his/her permissions are made available in the |
| `template context`_ when you use ``RequestContext``. |
| |
| .. admonition:: Technicality |
| |
| Technically, these variables are only made available in the template context |
| if you use ``RequestContext`` *and* your ``TEMPLATE_CONTEXT_PROCESSORS`` |
| setting contains ``"django.core.context_processors.auth"``, which is default. |
| For more, see the `RequestContext docs`_. |
| |
| .. _RequestContext docs: ../templates_python/#subclassing-context-requestcontext |
| |
| Users |
| ----- |
| |
| The currently logged-in user, either a ``User`` instance or an``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 ``django.core.context_processors.PermWrapper``, |
| which is a template-friendly proxy of permissions. |
| |
| In the ``{{ perms }}`` object, single-attribute lookup is a proxy to |
| ``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 ``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 %} |
| |
| .. _template context: ../templates_python/ |
| |
| 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 ``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: |
| |
| * To create a new message, use |
| ``user_obj.message_set.create(message='message_text')``. |
| * To retrieve/delete messages, use ``user_obj.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 ``RequestContext``, the currently logged-in user and his/her |
| messages are made available in the `template context`_ 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 ``RequestContext`` calls ``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 `session framework`_. |
| |
| .. _session framework: ../sessions/ |
| |
| 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 |
| ``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 |
| ``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, ``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 ``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(id)`` and ``authenticate(**credentials)``. |
| |
| The ``get_user`` method takes an ``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 |