Streamlining Access Control in Django with Role-Based Access Control (RBAC) 🔒

Implementing secure access control strategies using RBAC in Django.

30 Sep 2024   Laban Kibet   · 16 mins read
Tags: Django, Security, RBAC

Streamlining Access Control in Django with Role-Based Access Control (RBAC)

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.

Table of Contents

  1. Overview of Django Authentication and Authorization
  2. Step-by-Step Implementation of RBAC
  3. Performing Access Control Checks: Applying Permissions
  4. Conclusion

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.

Prerequisites

Before diving into this article, please ensure you meet the following requirements:

  • Familiarity with Python and Django: A basic understanding of Python programming and the Django framework is essential for following along.
  • Python Version: Ensure that Python version 3.7 or higher is installed on your system.

    Overview of Django Authentication and Authorization

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):

  • User: This component represents individual users within the application, allowing for personalized access management.
  • Group: This component allows for the categorization of users into various groups. For our RBAC implementation, we will utilize the group model to define user roles.
  • Permission: This component outlines the specific actions users can perform within the application, enabling fine-grained control over access rights.

In the following sections, we will explore each of these components in greater detail during the implementation walkthrough.

Walkthrough of Implementation of RBAC

Example Case Study: E-Commerce Platform

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.

User, Group, and Permission

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.

Django Admin Site

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.

Product Review Record

To create the Product Review Record model, follow these steps:

  1. Create the App: Start by creating a new app named reviews by running the following command:

    python manage.py startapp reviews
  1. Define the Model: Open the 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}"

  1. Update Settings: Add the newly created app to the INSTALLED_APPS list in your settings.py file:

    
    INSTALLED_APPS = [
        # Other apps...
        'reviews',
    ] 
    
  2. Create Database Tables: Run the following commands to create the table for the Product Review model:

    python manage.py makemigrations
    python manage.py migrate` 
    
  3. 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"] 
    
  4. Access the Admin Site: Log in to the Django admin site to view the newly created table.

Admin Site Screenshot

Creating Roles

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.

Creating Roles Screenshot

Default Permissions

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:

  • Can view: Grants read access to instances of the model.
  • Can change: Grants update access to instances of the model.
  • Can add: Grants create access to instances of the model.
  • Can delete: Grants delete access to instances of the model.

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.

Managing User, Group, and Permission Programmatically

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.

  1. Open the Shell: Start by running the following command in your terminal:

    python manage.py shell` 
  1. Create the Reviewer Group: In the shell, import the 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')
  1. 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:

    • name (Required): A brief description (up to 255 characters).
    • content_type (Required): A reference to the django_content_type database table, which records each installed model.
    • codename (Required): A unique identifier (up to 100 characters).

    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.

  2. Assigning Permissions: Let’s assign the Reviewer group one of those default permissions programmatically. To do this, perform the following steps in the shell:

    • Import the Permissions and ContentType Models:
    
        
    from django.contrib.contenttypes.models import ContentType
    from django.contrib.auth.models import Permission
    
    • Get the Content Type for the Product Review Model:
    
    content_type = ContentType.objects.get(app_label='reviews', model='productreview')
    
    • Get the Permission Object:
    
    permission = Permission.objects.get(codename='view_productreview', content_type=content_type)
    
    • Add the Permission Object to the Many-to-Many Field:
    
    reviewer_group.permissions.add(permission)
    
  3. 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:

    • Get Content Types:
    user_content_type = ContentType.objects.get(app_label='auth', model='user')
    product_review_content_type = ContentType.objects.get(app_label='reviews', model='productreview')
    
    • Get All Permission Objects:
    user_permissions = Permission.objects.filter(content_type=user_content_type)
    review_permissions = Permission.objects.filter(content_type=product_review_content_type)
    
    • Create the Admin Group:
    admin_group = Group.objects.create(name='Admin')
    
    • Combine All Permission Objects:
    all_permissions = user_permissions | review_permissions 
    
    
    • Assign Combined Permissions to the Admin Group:
    
        admin_group.permissions.set(all_permissions)
    

Performing Access Control Checks - Applying 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!

Conclusion

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.