diff options
| author | Jon Janzen <jon@jonjanzen.com> | 2024-03-31 12:29:10 -0700 |
|---|---|---|
| committer | Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> | 2024-10-07 14:19:41 +0200 |
| commit | 50f89ae850f6b4e35819fe725a08c7e579bfd099 (patch) | |
| tree | 856a0e954e0be928c55f6070f2ac8b766459b3e7 /docs | |
| parent | 4cad317ff1f9a79d54c1d5b12f1ccbd260ca009f (diff) | |
Fixed #35303 -- Implemented async auth backends and utils.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/ref/contrib/auth.txt | 144 | ||||
| -rw-r--r-- | docs/releases/5.2.txt | 30 | ||||
| -rw-r--r-- | docs/topics/auth/customizing.txt | 29 |
3 files changed, 202 insertions, 1 deletions
diff --git a/docs/ref/contrib/auth.txt b/docs/ref/contrib/auth.txt index d5fc724b54..c8699a2913 100644 --- a/docs/ref/contrib/auth.txt +++ b/docs/ref/contrib/auth.txt @@ -197,13 +197,23 @@ Methods been called for this user. .. method:: get_user_permissions(obj=None) + .. method:: aget_user_permissions(obj=None) + + *Asynchronous version*: ``aget_user_permissions()`` Returns a set of permission strings that the user has directly. If ``obj`` is passed in, only returns the user permissions for this specific object. + .. versionchanged:: 5.2 + + ``aget_user_permissions()`` method was added. + .. method:: get_group_permissions(obj=None) + .. method:: aget_group_permissions(obj=None) + + *Asynchronous version*: ``aget_group_permissions()`` Returns a set of permission strings that the user has, through their groups. @@ -211,7 +221,14 @@ Methods If ``obj`` is passed in, only returns the group permissions for this specific object. + .. versionchanged:: 5.2 + + ``aget_group_permissions()`` method was added. + .. method:: get_all_permissions(obj=None) + .. method:: aget_all_permissions(obj=None) + + *Asynchronous version*: ``aget_all_permissions()`` Returns a set of permission strings that the user has, both through group and user permissions. @@ -219,7 +236,14 @@ Methods If ``obj`` is passed in, only returns the permissions for this specific object. + .. versionchanged:: 5.2 + + ``aget_all_permissions()`` method was added. + .. method:: has_perm(perm, obj=None) + .. method:: ahas_perm(perm, obj=None) + + *Asynchronous version*: ``ahas_perm()`` Returns ``True`` if the user has the specified permission, where perm is in the format ``"<app label>.<permission codename>"``. (see @@ -230,7 +254,14 @@ Methods If ``obj`` is passed in, this method won't check for a permission for the model, but for this specific object. + .. versionchanged:: 5.2 + + ``ahas_perm()`` method was added. + .. method:: has_perms(perm_list, obj=None) + .. method:: ahas_perms(perm_list, obj=None) + + *Asynchronous version*: ``ahas_perms()`` Returns ``True`` if the user has each of the specified permissions, where each perm is in the format @@ -241,13 +272,24 @@ Methods If ``obj`` is passed in, this method won't check for permissions for the model, but for the specific object. + .. versionchanged:: 5.2 + + ``ahas_perms()`` method was added. + .. method:: has_module_perms(package_name) + .. method:: ahas_module_perms(package_name) + + *Asynchronous version*: ``ahas_module_perms()`` 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``. For an active superuser, this method will always return ``True``. + .. versionchanged:: 5.2 + + ``ahas_module_perms()`` method was added. + .. method:: email_user(subject, message, from_email=None, **kwargs) Sends an email to the user. If ``from_email`` is ``None``, Django uses @@ -264,6 +306,9 @@ Manager methods by :class:`~django.contrib.auth.models.BaseUserManager`): .. method:: create_user(username, email=None, password=None, **extra_fields) + .. method:: acreate_user(username, email=None, password=None, **extra_fields) + + *Asynchronous version*: ``acreate_user()`` Creates, saves and returns a :class:`~django.contrib.auth.models.User`. @@ -285,11 +330,22 @@ Manager methods See :ref:`Creating users <topics-auth-creating-users>` for example usage. + .. versionchanged:: 5.2 + + ``acreate_user()`` method was added. + .. method:: create_superuser(username, email=None, password=None, **extra_fields) + .. method:: acreate_superuser(username, email=None, password=None, **extra_fields) + + *Asynchronous version*: ``acreate_superuser()`` Same as :meth:`create_user`, but sets :attr:`~models.User.is_staff` and :attr:`~models.User.is_superuser` to ``True``. + .. versionchanged:: 5.2 + + ``acreate_superuser()`` method was added. + .. method:: with_perm(perm, is_active=True, include_superusers=True, backend=None, obj=None) Returns users that have the given permission ``perm`` either in the @@ -499,23 +555,51 @@ The following backends are available in :mod:`django.contrib.auth.backends`: methods. By default, it will reject any user and provide no permissions. .. method:: get_user_permissions(user_obj, obj=None) + .. method:: aget_user_permissions(user_obj, obj=None) + + *Asynchronous version*: ``aget_user_permissions()`` Returns an empty set. + .. versionchanged:: 5.2 + + ``aget_user_permissions()`` function was added. + .. method:: get_group_permissions(user_obj, obj=None) + .. method:: aget_group_permissions(user_obj, obj=None) + + *Asynchronous version*: ``aget_group_permissions()`` Returns an empty set. + .. versionchanged:: 5.2 + + ``aget_group_permissions()`` function was added. + .. method:: get_all_permissions(user_obj, obj=None) + .. method:: aget_all_permissions(user_obj, obj=None) + + *Asynchronous version*: ``aget_all_permissions()`` Uses :meth:`get_user_permissions` and :meth:`get_group_permissions` to get the set of permission strings the ``user_obj`` has. + .. versionchanged:: 5.2 + + ``aget_all_permissions()`` function was added. + .. method:: has_perm(user_obj, perm, obj=None) + .. method:: ahas_perm(user_obj, perm, obj=None) + + *Asynchronous version*: ``ahas_perm()`` Uses :meth:`get_all_permissions` to check if ``user_obj`` has the permission string ``perm``. + .. versionchanged:: 5.2 + + ``ahas_perm()`` function was added. + .. class:: ModelBackend This is the default authentication backend used by Django. It @@ -539,6 +623,9 @@ The following backends are available in :mod:`django.contrib.auth.backends`: unlike others methods it returns an empty queryset if ``obj is not None``. .. method:: authenticate(request, username=None, password=None, **kwargs) + .. method:: aauthenticate(request, username=None, password=None, **kwargs) + + *Asynchronous version*: ``aauthenticate()`` Tries to authenticate ``username`` with ``password`` by calling :meth:`User.check_password @@ -552,38 +639,77 @@ The following backends are available in :mod:`django.contrib.auth.backends`: if it wasn't provided to :func:`~django.contrib.auth.authenticate` (which passes it on to the backend). + .. versionchanged:: 5.2 + + ``aauthenticate()`` function was added. + .. method:: get_user_permissions(user_obj, obj=None) + .. method:: aget_user_permissions(user_obj, obj=None) + + *Asynchronous version*: ``aget_user_permissions()`` Returns the set of permission strings the ``user_obj`` has from their own user permissions. Returns an empty set if :attr:`~django.contrib.auth.models.AbstractBaseUser.is_anonymous` or :attr:`~django.contrib.auth.models.CustomUser.is_active` is ``False``. + .. versionchanged:: 5.2 + + ``aget_user_permissions()`` function was added. + .. method:: get_group_permissions(user_obj, obj=None) + .. method:: aget_group_permissions(user_obj, obj=None) + + *Asynchronous version*: ``aget_group_permissions()`` Returns the set of permission strings the ``user_obj`` has from the permissions of the groups they belong. Returns an empty set if :attr:`~django.contrib.auth.models.AbstractBaseUser.is_anonymous` or :attr:`~django.contrib.auth.models.CustomUser.is_active` is ``False``. + .. versionchanged:: 5.2 + + ``aget_group_permissions()`` function was added. + .. method:: get_all_permissions(user_obj, obj=None) + .. method:: aget_all_permissions(user_obj, obj=None) + + *Asynchronous version*: ``aget_all_permissions()`` Returns the set of permission strings the ``user_obj`` has, including both user permissions and group permissions. Returns an empty set if :attr:`~django.contrib.auth.models.AbstractBaseUser.is_anonymous` or :attr:`~django.contrib.auth.models.CustomUser.is_active` is ``False``. + + .. versionchanged:: 5.2 + + ``aget_all_permissions()`` function was added. .. method:: has_perm(user_obj, perm, obj=None) + .. method:: ahas_perm(user_obj, perm, obj=None) + + *Asynchronous version*: ``ahas_perm()`` Uses :meth:`get_all_permissions` to check if ``user_obj`` has the permission string ``perm``. Returns ``False`` if the user is not :attr:`~django.contrib.auth.models.CustomUser.is_active`. + .. versionchanged:: 5.2 + + ``ahas_perm()`` function was added. + .. method:: has_module_perms(user_obj, app_label) + .. method:: ahas_module_perms(user_obj, app_label) + + *Asynchronous version*: ``ahas_module_perms()`` Returns whether the ``user_obj`` has any permissions on the app ``app_label``. + .. versionchanged:: 5.2 + + ``ahas_module_perms()`` function was added. + .. method:: user_can_authenticate() Returns whether the user is allowed to authenticate. To match the @@ -637,6 +763,9 @@ The following backends are available in :mod:`django.contrib.auth.backends`: created if not already in the database Defaults to ``True``. .. method:: authenticate(request, remote_user) + .. method:: aauthenticate(request, remote_user) + + *Asynchronous version*: ``aauthenticate()`` The username passed as ``remote_user`` is considered trusted. This method returns the user object with the given username, creating a new @@ -651,6 +780,10 @@ The following backends are available in :mod:`django.contrib.auth.backends`: if it wasn't provided to :func:`~django.contrib.auth.authenticate` (which passes it on to the backend). + .. versionchanged:: 5.2 + + ``aauthenticate()`` function was added. + .. method:: clean_username(username) Performs any cleaning on the ``username`` (e.g. stripping LDAP DN @@ -658,12 +791,17 @@ The following backends are available in :mod:`django.contrib.auth.backends`: the cleaned username. .. method:: configure_user(request, user, created=True) + .. method:: aconfigure_user(request, user, created=True) + + *Asynchronous version*: ``aconfigure_user()`` Configures the user on each authentication attempt. This method is called immediately after fetching or creating the user being authenticated, and can be used to perform custom setup actions, such as setting the user's groups based on attributes in an LDAP directory. - Returns the user object. + Returns the user object. When fetching or creating an user is called + from a synchronous context, ``configure_user`` is called, + ``aconfigure_user`` is called from async contexts. The setup can be performed either once when the user is created (``created`` is ``True``) or on existing users (``created`` is @@ -674,6 +812,10 @@ The following backends are available in :mod:`django.contrib.auth.backends`: if it wasn't provided to :func:`~django.contrib.auth.authenticate` (which passes it on to the backend). + .. versionchanged:: 5.2 + + ``aconfigure_user()`` function was added. + .. method:: user_can_authenticate() Returns whether the user is allowed to authenticate. This method diff --git a/docs/releases/5.2.txt b/docs/releases/5.2.txt index c445e02694..9aa232b902 100644 --- a/docs/releases/5.2.txt +++ b/docs/releases/5.2.txt @@ -52,6 +52,36 @@ Minor features * The default iteration count for the PBKDF2 password hasher is increased from 870,000 to 1,000,000. +* The following new asynchronous methods on are now provided, using an ``a`` + prefix: + + * :meth:`.UserManager.acreate_user` + * :meth:`.UserManager.acreate_superuser` + * :meth:`.BaseUserManager.aget_by_natural_key` + * :meth:`.User.aget_user_permissions()` + * :meth:`.User.aget_all_permissions()` + * :meth:`.User.aget_group_permissions()` + * :meth:`.User.ahas_perm()` + * :meth:`.User.ahas_perms()` + * :meth:`.User.ahas_module_perms()` + * :meth:`.User.aget_user_permissions()` + * :meth:`.User.aget_group_permissions()` + * :meth:`.User.ahas_perm()` + * :meth:`.ModelBackend.aauthenticate()` + * :meth:`.ModelBackend.aget_user_permissions()` + * :meth:`.ModelBackend.aget_group_permissions()` + * :meth:`.ModelBackend.aget_all_permissions()` + * :meth:`.ModelBackend.ahas_perm()` + * :meth:`.ModelBackend.ahas_module_perms()` + * :meth:`.RemoteUserBackend.aauthenticate()` + * :meth:`.RemoteUserBackend.aconfigure_user()` + +* Auth backends can now provide async implementations which are used when + calling async auth functions (e.g. + :func:`~.django.contrib.auth.aauthenticate`) to reduce context-switching which + improves performance. See :ref:`adding an async interface + <writing-authentication-backends-async-interface>` for more details. + :mod:`django.contrib.contenttypes` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/auth/customizing.txt b/docs/topics/auth/customizing.txt index f41b10fb4a..6fdcd136c0 100644 --- a/docs/topics/auth/customizing.txt +++ b/docs/topics/auth/customizing.txt @@ -790,10 +790,17 @@ utility methods: email address. .. method:: models.BaseUserManager.get_by_natural_key(username) + .. method:: models.BaseUserManager.aget_by_natural_key(username) + + *Asynchronous version*: ``aget_by_natural_key()`` Retrieves a user instance using the contents of the field nominated by ``USERNAME_FIELD``. + .. versionchanged:: 5.2 + + ``aget_by_natural_key()`` method was added. + Extending Django's default ``User`` ----------------------------------- @@ -1186,3 +1193,25 @@ Finally, specify the custom model as the default user model for your project using the :setting:`AUTH_USER_MODEL` setting in your ``settings.py``:: AUTH_USER_MODEL = "customauth.MyUser" + +.. _writing-authentication-backends-async-interface: + +Adding an async interface +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + +To optimize performance when called from an async context authentication, +backends can implement async versions of each function - ``aget_user(user_id)`` +and ``aauthenticate(request, **credentials)``. When an authentication backend +extends ``BaseBackend`` and async versions of these functions are not provided, +they will be automatically synthesized with ``sync_to_async``. This has +:ref:`performance penalties <async_performance>`. + +While an async interface is optional, a synchronous interface is always +required. There is no automatic synthesis for a synchronous interface if an +async interface is implemented. + +Django's out-of-the-box authentication backends have native async support. If +these native backends are extended take special care to make sure the async +versions of modified functions are modified as well. |
