Miscellaneous Utilities
Note
This page is for developers who want to customize or extend OpenWISP Users, whether for bug fixes, new features, or contributions.
For user guides and general information, please see:
This section covers miscellaneous utilities provided by the OpenWISP Users module.
Organization Membership Helpers
The User
model offers methods to efficiently check whether the user is
a member, manager, or owner of an organization.
Use these methods to distinguish between different user roles across organizations and minimize database queries.
import swapper
User = swapper.load_model("openwisp_users", "User")
Organization = swapper.load_model("openwisp_users", "Organization")
user = User.objects.first()
org = Organization.objects.first()
user.is_member(org)
user.is_manager(org)
user.is_owner(org)
# Also valid (avoids query to retrieve Organization instance)
device = Device.objects.first()
user.is_member(device.organization_id)
user.is_manager(device.organization_id)
user.is_owner(device.organization_id)
is_member(org)
Returns True
if the user is a member of the specified Organization
instance. Alternatively, you can pass a UUID
or str
representing
the organization's primary key, which allows you to avoid an additional
database query to fetch the organization instance.
Use this check to grant access to end-users who need to consume services offered by organizations they're members of, such as authenticating to public WiFi services.
is_manager(org)
Returns True
if the user is a member of the specified Organization
instance and has the OrganizationUser.is_admin
field set to True
.
Alternatively, you can pass a UUID
or str
representing the
organization's primary key, which allows you to avoid an additional
database query to fetch the organization instance.
Use this check to grant access to managers of organizations, who need to perform administrative tasks such as creating, editing, or deleting objects of their organization, or accessing sensitive information like firmware images.
is_owner(org)
Returns True
if the user is a member of the specified Organization
instance and is the owner of the organization, checked against the
presence of an OrganizationOwner
instance for the user. Alternatively,
you can pass a UUID
or str
representing the organization's primary
key, which allows you to avoid an additional database query to fetch the
organization instance.
Use this check to prevent managers from taking control of organizations without the original owner's consent.
organizations_dict
The methods described above utilize the organizations_dict
property
method, which builds a dictionary containing the primary keys of
organizations the user is a member of, along with information about
whether the user is a manager (is_admin
) or owner (is_owner
).
This data structure is cached automatically to prevent multiple database queries across multiple requests.
The cache is automatically invalidated on the following events:
An
OrganizationUser
is added, changed, or deleted.An
OrganizationOwner
is added, changed, or deleted.The
is_active
field of anOrganization
changes.
Usage example:
>>> user.organizations_dict
... {'20135c30-d486-4d68-993f-322b8acb51c4': {'is_admin': True, 'is_owner': False}}
>>> user.organizations_dict.keys()
... dict_keys(['20135c30-d486-4d68-993f-322b8acb51c4'])
organizations_managed
Returns a list of primary keys of organizations the user can manage.
Usage example:
>>> user.organizations_managed
... ['20135c30-d486-4d68-993f-322b8acb51c4']
organizations_owned
Returns a list of primary keys of organizations the user owns.
Usage example:
>>> user.organizations_owned
... ['20135c30-d486-4d68-993f-322b8acb51c4']
UsersAuthenticationBackend
Full python path:
openwisp_users.backends.UsersAuthenticationBackend
.
This authentication backend enables users to authenticate using their email or phone number, as well as their username. Email authentication takes precedence over the username, while phone number authentication takes precedence if the identifier passed as argument is a valid phone number.
Phone numbers are parsed using the phonenumbers library, ensuring recognition even if users include characters like spaces, dots, or dashes.
The OPENWISP_USERS_AUTH_BACKEND_AUTO_PREFIXES setting allows specifying a list of international prefixes that can be automatically prepended to the username string, enabling users to log in without typing the international prefix.
Additionally, the backend supports phone numbers with a leading zero, ensuring successful authentication even with the leading zero included.
You can also use the backend programmatically:
from openwisp_users.backends import UsersAuthenticationBackend
backend = UsersAuthenticationBackend()
backend.authenticate(request, identifier, password)
PasswordExpirationMiddleware
Full python path:
openwisp_users.middleware.PasswordExpirationMiddleware
.
When the password expiration feature is enabled (see OPENWISP_USERS_USER_PASSWORD_EXPIRATION and OPENWISP_USERS_STAFF_USER_PASSWORD_EXPIRATION), this middleware restricts users to the password change view until they change their password.
Ensure this middleware follows AuthenticationMiddleware
and
MessageMiddleware
:
# in your_project/settings.py
MIDDLEWARE = [
# Other middlewares
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"openwisp_users.middleware.PasswordExpirationMiddleware",
]
PasswordReuseValidator
Full python path:
openwisp_users.password_validation.PasswordReuseValidator
.
On password change views, this validator ensures users cannot reuse their current password as the new password.
Add the validator to the AUTH_PASSWORD_VALIDATORS
Django setting:
# in your-project/settings.py
AUTH_PASSWORD_VALIDATORS = [
# Other password validators
{
"NAME": "openwisp_users.password_validation.PasswordReuseValidator",
},
]