Authorization
Beyond authentication (verifying who a user is), authorization controls what an authenticated user is allowed to do.
The framework provides a flexible and robust system to define and enforce permissions, ensuring users can only access the resources and functionalities they are authorized for.
—
1. Permissions System: Role-Based Access Control (RBAC) for Standard Users
The core of the standard user authorization system is built around a Role-Based Access Control (RBAC) model, allowing you to define granular permissions and organize them effectively for your application’s regular users.
``UserPermission`` Model: This model represents individual, distinct permissions (e.g.,
blog.add_post,users.view_profile). You can define as many specific permissions as your application needs for its regular user base.``Group`` Model: Groups act as roles for standard users. You can create groups (e.g., “Editors”, “Moderators”, “Managers”) and assign a collection of
UserPermissionobjects to each group. This simplifies permission management, as you assign users to groups rather than individually assigning many permissions to each user.``User`` Model: Users are then assigned to one or more
Groupobjects. A user inherits all permissions from the groups they belong to. TheUsermodel includes a robusthas_permission(permission_name: str) -> boolmethod which efficiently checks if a user possesses a specific permission, considering their group memberships.
Key Features (Standard Users):
Granular Control: Define specific permissions that represent actions or access rights for standard users.
Efficient Checks: The
has_permissionmethod on theUsermodel uses caching to optimize performance, reducing database queries for frequently checked permissions.
—
2. Managing Permissions, Groups, and Users for Standard Users
The framework’s generic Admin Panel provides a convenient interface for managing your standard user authorization structure:
Adding Permissions: Through the Admin Panel, you can define new
UserPermissionentries, giving them a unique name and an optional description. These represent the individual capabilities in your system.Creating Groups: You can create new
Groupobjects (roles) and assign a name and description.Assigning Permissions to Groups: Crucially, the Admin Panel allows you to easily associate any defined
UserPermissionwith specificGroupobjects. For example, you could create an “Editor” group and assign itblog.add_post,blog.edit_post, andblog.delete_postpermissions.Assigning Users to Groups: Finally, you can assign individual
Useraccounts to one or moreGroupobjects. A user will then inherit all permissions from the groups they are a member of.
This integrated approach means you don’t have to write custom code for basic permission management; it’s all handled through the Admin Panel.
—
3. Admin User Permissions and Hierarchy
The framework implements a distinct and robust permission system specifically for administrative users, operating separately from the standard user permission structure. This section details the permission hierarchy for admin users and how these permissions interact with the generic admin panel views.
#### Admin User Types and Their Privileges
The administrative users in your system are categorized into three distinct types, each with varying levels of access and control:
Supreme Admin (User ID 1): The Ultimate Authority * Identification: This is typically the very first admin user created in the system, uniquely identified by having an
idof1in the database. * Permissions: This user automatically possesses all possible permissions across the entire system. They bypass all explicit permission checks and can perform any action, including creating, modifying, and deleting any data or user, including other admin users (Super-admin and Regular Admin types). This user represents the absolute highest level of administrative control.Super-admin (``is_superuser=True``): Elevated Administrative Control * Identification: These admin users are designated by having their
is_superuserflag explicitly set toTruein their admin user profile. * Permissions: ASuper-adminuser inherently receives a broad set of elevated permissions across the system. They can manage their own data and, crucially, have the authority to modify and delete data of Regular Admin users. However, they cannot modify or delete theSupreme Admin(ID 1) or otherSuper-adminusers, unless explicitly granted specific additional permissions via the Admin User Groups. * Control: They are typically responsible for managing the daily administrative operations and overseeing Regular Administrators.Regular Admin: Standard Administrative Access * Identification: These are administrative users whose
is_superuserflag isFalse. Their administrative access is governed by the specific permissions assigned to them through their associated Admin User Groups. * Permissions: Their access is strictly limited to the permissions explicitly granted to them. For example, a Regular Admin might haveadd_productandview_productpermissions but lackdelete_product. * Control: They can only manage the data and sections for which they have explicit permissions. They cannot modify or delete other admin users (neitherSupreme Admin,Super-admin, nor otherRegular Admins) unless specific administrative management permissions are assigned to their Admin User Groups (which is generally restricted to higher-tier admins).
—
#### Generic Admin Panel Permissions Enforcement (@PermissionRequired)
The framework’s generic admin panel views are protected by the @PermissionRequired decorator. This decorator dynamically checks if the authenticated admin user has the necessary permission to access a specific view or perform an action on a model.
The permissions required for these generic views are dynamically constructed based on the action and the model_name being accessed. Here, model_name refers to the lowercase name of the database model (e.g., user, product, category) that the view is interacting with.
- Admin Dashboard Access:
Permission Required:
@PermissionRequired("view_dashboard")Description: Grants access to the main administrative dashboard.
- Add Object View:
Permission Required:
@PermissionRequired(lambda request: f"add_{request.path_params.get('model_name').lower()}" if request.path_params and request.path_params.get('model_name') else "add_unknown_model")Example: To add a new
Productvia the admin panel, the admin user needs theadd_productpermission.Description: Allows access to the form for creating a new instance of a specified model.
- Change Object View:
Permission Required:
@PermissionRequired(lambda request: f"change_{request.path_params.get('model_name').lower()}" if request.path_params and request.path_params.get('model_name') else "change_unknown_model")Example: To edit an existing
Userthrough the admin panel, the admin user needs thechange_userpermission.Description: Allows access to the form for modifying an existing instance of a specified model.
- List Objects View:
Permission Required:
@PermissionRequired(lambda request: f"view_{request.path_params.get('model_name').lower()}" if request.path_params and request.path_params.get('model_name') else "view_unknown_model")Example: To view the list of
Productsin the admin panel, the admin user needs theview_productpermission.Description: Allows admin users to view a list of all instances for a specified model.
- Detail Object View:
Permission Required:
@PermissionRequired(lambda request: f"view_{request.path_params.get('model_name').lower()}" if request.path_params and request.path_params.get('model_name') else "view_unknown_model")Example: To view the detailed information of a single
Userin the admin panel, the admin user needs theview_userpermission.Description: Allows admin users to view the detailed information of a single instance of a specified model.
- Delete Object View:
Permission Required:
@PermissionRequired(lambda request: f"delete_{request.path_params.get('model_name').lower()}" if request.path_params and request.path_params.get('model_name') else "delete_unknown_model")Example: To delete a
Categoryvia the admin panel, the admin user needs thedelete_categorypermission.Description: Allows admin users to delete an instance of a specified model.
Important Note on Dynamic Permissions: The lambda function within @PermissionRequired dynamically constructs the required permission string based on the model_name extracted from the URL path parameters. This ensures that permissions are granular and model-specific. If model_name is not found, a default “unknown_model” permission is used, which typically denies access.
—
#### Admin Panel Group and Role Management for Admin Users
Admin user permissions are managed within the framework’s Admin Panel itself under the Authentication & Authorization section. This is where you configure the specific administrative roles and their corresponding permissions.
Create and Manage Admin User Groups: Define new groups specifically for administrative roles (e.g.,
Content_Administrators,Product_Supervisors,System_Auditors).Assign Permissions to Admin Groups: Crucially, select specific administrative permissions (e.g.,
admin.add_user_permission,app_name.change_order,app_name.delete_product) and assign them to the relevant Admin User Groups.Assign Admin Users to Admin Groups: Finally, assign individual Admin User accounts to one or more Admin User Groups. An admin user will then inherit all permissions from the admin groups they are a member of.
Manage ``is_superuser`` Flag: For
Super-adminusers, ensure theiris_superuserflag is explicitly set toTruein their individual admin user profile within the Admin Panel.
By carefully configuring Admin User Groups and assigning the appropriate permissions, you can precisely control access levels for all your administrative users, ensuring secure and efficient management of your application.
—
4. Enforcing Authorization with PermissionRequired Decorator (General Usage)
The primary way to enforce authorization on your views, for both standard users and admin users, is by using the PermissionRequired decorator. This decorator ensures that only users (of any type) with the necessary permissions can access a particular view.
How to Use:
You can apply the PermissionRequired decorator to your view functions or methods. It accepts one or more permission strings:
Single Permission:
# myapp/views.py from lback.auth.permissions import PermissionRequired from lback.utils.shortcuts import render @PermissionRequired("blog.view_posts") def view_blog_posts(request): # This view requires the 'blog.view_posts' permission # ... fetch blog posts ... return render(request, "blog/list.html", {"posts": posts})
Multiple Permissions (User needs ALL of them):
# myapp/views.py from lback.auth.permissions import PermissionRequired from lback.utils.shortcuts import render @PermissionRequired(["blog.add_post", "blog.publish_post"]) def create_and_publish_post(request): # This view requires BOTH 'blog.add_post' AND 'blog.publish_post' permissions # ... logic to create and publish a post ... return render(request, "blog/new_post_success.html")
- Dynamic Permissions (Permissions based on request context):
For more complex scenarios, you can provide a callable (a function) to
PermissionRequired. This function will receive therequestobject and should return the required permission(s) dynamically.# myapp/views.py from lback.auth.permissions import PermissionRequired from lback.utils.shortcuts import render def get_dynamic_edit_permission(request): # Example: permission based on the type of user or object being edited if request.user and request.user.is_staff: # Assuming 'is_staff' property on User model return "article.edit_all" return "article.edit_own" @PermissionRequired(get_dynamic_edit_permission) def edit_article_view(request, article_id): # Permissions are determined by the 'get_dynamic_edit_permission' function at runtime # ... logic to edit an article ... return render(request, "articles/edit.html", {"article_id": article_id})
—
5. Permission Check Flow & Denied Access Handling
When a view decorated with PermissionRequired is accessed:
The framework attempts to retrieve the authenticated
userobject from therequest.If the user is a Supreme Admin (User ID 1) or a Super-admin (
is_superuser=True), access is immediately granted.Otherwise, the system calls the
user.has_permission()method for each required permission.If the user lacks any of the specified permissions, access is denied.
Denied Access Handling: * If the user is not authenticated at all, they are redirected to the login page (
/auth/login/) with a flash message. * If the user is authenticated but lacks the required permissions, they are redirected to a 403 Forbidden page (return_403) with a flash message indicating denied access.
—
6. Signals for Authorization Flow
The authorization process also dispatches signals, allowing you to hook into the permission checking lifecycle for custom logic or logging:
permission_check_started: Broadcast when a permission check begins.Sender:
PermissionRequiredinstanceKwargs:
request,required_permissions(set of permissions being checked),user(the user object),view_func_name(name of the view function).
permission_check_succeeded: Broadcast when a user successfully passes a permission check.Sender:
PermissionRequiredinstanceKwargs:
request,required_permissions,user,view_func_name.
permission_check_failed: Broadcast when a user fails a permission check.Sender:
PermissionRequiredinstanceKwargs:
request,required_permissions,user,view_func_name,reason(e.g., “user_not_authenticated”, “permission_missing”).