Access control is a crucial element in any application that demands data security, privacy, and regulated access. Its primary purpose is to manage and restrict what each user can do or access within the system.
While various models of access control exist, this guide will focus specifically on Role-Based Access Control (RBAC) and its implementation in Django.
In this guide, we will leverage Django’s built-in authentication system to control user access to resources and actions based on the permissions tied to their assigned roles.
Before diving into this article, please ensure you meet the following requirements:
Django, as a powerful and feature-rich Python framework, includes a comprehensive authentication system designed to streamline user management and access control. This system encompasses both authentication—the process of identifying users—and authorization—the mechanism of managing permissions.
The built-in authentication system provides several key components that facilitate the implementation of Role-Based Access Control (RBAC):
In the following sections, we will explore each of these components in greater detail during the implementation walkthrough.
In this section, we will implement Role-Based Access Control (RBAC) for an E-Commerce Platform to demonstrate how RBAC can effectively manage user permissions.
Roles in the System:
Customer: Can view products, add items to their cart, and place orders. They have limited access to their account settings.
Admin: Can manage all aspects of the platform, including creating, updating, viewing, and deleting product listings, managing customer accounts, and overseeing orders.
Support Staff: Can view customer orders and assist customers with inquiries but cannot modify product listings or manage accounts.
In this case study, the primary resource we will be restricting access to includes product listings and customer orders. By defining these roles and their permissions, we can ensure that users only have access to the functionalities relevant to their role in the system.
As previously mentioned, Django’s authentication system includes a built-in User model, which is essential for managing user accounts. This authentication system is packaged as part of the django.contrib.auth application, providing the core functionality and models needed for user management.
By default, the authentication system is included in every project created with the django-admin startproject
command, as it is listed in the INSTALLED_APPS
setting within the settings.py
file.
To initialize the necessary database tables for the default models, run the command:
python manage.py migrate
This action will create the tables for the User, Group, and Permission models, making them available for use in your application.
Note: There is a many-to-many relationship between User and Permission as well as between Group and Permission, allowing for flexible permission management.
To facilitate the interactive creation and management of these objects, we need to set up a superuser account that can access the Django admin dashboard. To create a superuser, run the following command:
python manage.py createsuperuser
After creating the superuser, navigate to the following URL to access the admin interface:
[http://127.0.0.1:8000/admin/](http://127.0.0.1:8000/admin/)
Log in using the superuser credentials you just created to manage users, groups, and permissions through the intuitive admin dashboard.
To create the Product Review Record model, follow these steps:
python manage.py startapp reviews
models.py
file in the reviews application and add the following code:from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.name
class ProductReview(models.Model):
product = models.ForeignKey('Product', on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
rating = models.IntegerField()
comment = models.TextField()
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return f"Review by {self.user.username} for {self.product.name} - Rating: {self.rating}"
Update Settings: Add the newly created app to the INSTALLED_APPS
list in your settings.py
file:
INSTALLED_APPS = [
# Other apps...
'reviews',
]
Create Database Tables: Run the following commands to create the table for the Product Review model:
python manage.py makemigrations
python manage.py migrate`
Register the Model in Admin: To make the model manageable from the Django admin interface, register it in the admin.py
file of the reviews application:
from django.contrib import admin
from .models import ProductReview
@admin.register(ProductReview)
class ProductReviewAdmin(admin.ModelAdmin):
list_display = ["id", "user", "product", "rating", "created_at"]
Access the Admin Site: Log in to the Django admin site to view the newly created table.
We will utilize the Group model to represent roles within the application. To create a Reviewer group, navigate to the admin dashboard and follow the prompts to set up the group, allowing specific users to manage product reviews.
In the previous section, we created a Reviewer group and assigned specific permissions through the Django admin interface. If you’ve wondered about the source of those permissions, here’s the explanation:
For every model created in Django, four default permissions are automatically generated:
As a result, when we created the Product Review model, these four default permissions were established, which is why they are available in the permissions list when creating the Reviewer group.
We have previously used the Django admin dashboard to create a Reviewer group. However, we can also perform this programmatically. Let’s walk through the steps to achieve that.
python manage.py shell`
Group
model from the authentication application and create the Reviewer group as follows:
from django.contrib.auth.models import Group
reviewer_group = Group.objects.create(name='Reviewer')
Adding Permissions to the Reviewer Group: To assign permissions to the Reviewer group, we will utilize the related manager for permissions:
reviewer_group.permissions.add(permission)
Before we begin adding permissions, let’s explore what a Permission object entails. Permission objects contain the following fields:
django_content_type
database table, which records each installed model.By default, four permissions are generated for every model. The naming convention for a permission is formatted as <APP_NAME>.<PERMISSION_CODENAME>
. For instance, the permission to view all instances of the product review model in our e-commerce application will be: reviews.view_productreview
.
Assigning Permissions: Let’s assign the Reviewer group one of those default permissions programmatically. To do this, perform the following steps in the shell:
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import Permission
content_type = ContentType.objects.get(app_label='reviews', model='productreview')
permission = Permission.objects.get(codename='view_productreview', content_type=content_type)
reviewer_group.permissions.add(permission)
Creating the Admin Role: Next, let’s create the Admin group and assign it permissions for creating, updating, viewing, and deleting users and product reviews programmatically:
user_content_type = ContentType.objects.get(app_label='auth', model='user')
product_review_content_type = ContentType.objects.get(app_label='reviews', model='productreview')
user_permissions = Permission.objects.filter(content_type=user_content_type)
review_permissions = Permission.objects.filter(content_type=product_review_content_type)
admin_group = Group.objects.create(name='Admin')
all_permissions = user_permissions | review_permissions
admin_group.permissions.set(all_permissions)
Now that we have discussed Users, Roles, and Permissions, it’s time to put these permissions into practice. Having roles and permissions defined does not automatically enforce access restrictions within the application. To effectively implement access control, we must conduct access control checks.
Access control checks allow us to utilize the permissions we’ve created to grant or deny users access to various parts of the application. Essentially, a user gains access to a privileged section of the application if they—or the group to which they belong—hold the necessary permissions.
To test for permissions, we can use the user.has_perm()
method. For example:
if user.has_perm('reviews.view_productreview'):
# Grant access
else:
# Deny access`
Note: The ModelBackend
caches permissions on the user object after the first retrieval, which is typically sufficient for most request-response cycles. However, if you add permissions and check them immediately (e.g., in a view or test), it’s advisable to re-fetch the user from the database to ensure that the newly associated permissions with user groups are effective.
In templates, you can access permissions associated with the authenticated user using the template variable ``.
For more in-depth information on Django permissions and the authentication system, refer to the Django documentation for comprehensive details and examples. Happy exploring!
This concludes our guide on managing user roles and permissions programmatically in a Django-based e-commerce application. By implementing Role-Based Access Control (RBAC), we can enhance the security and functionality of our application, ensuring that users have appropriate access to resources based on their roles.