Role-Based Access Control (RBAC): A Simple and Elegant Implementation - Part 1

DB Schema Design

In today's digital landscape, securing access to resources is paramount. Role-Based Access Control (RBAC) is a powerful approach to managing user permissions efficiently. This blog post will guide you through implementing RBAC in a simple yet elegant way, complete with schema examples and a straightforward architecture.

In Part 1, we’ll see how we can plan db schema for RBAC.

Understanding RBAC

RBAC is an approach to restricting system access to authorized users based on their roles within an organization. It's a method of regulating access to computer or network resources based on the roles of individual users.

The Architecture

Let's start with a high-level view of our RBAC architecture:

In this architecture:

  1. Users are associated with roles

  2. Roles contain permissions

  3. All data is stored in Redis for fast access

  4. The application queries Redis and enforces permissions

Schema Design

Now, let's dive into the schema design for our RBAC system. We'll use two main tables: users and roles.

Users Table

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    role_id INTEGER NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Roles Table

CREATE TABLE roles (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50) UNIQUE NOT NULL,
    description TEXT,
    parent_role_id INTEGER,
    permissions JSONB NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Notice the permissions field in the roles table. This JSONB field will store our permissions in a flexible JSON format.

Permissions Structure

The permissions in our RBAC system are structured as a JSON object. Here's an example of what the permissions field might look like:

{
  "user_management": ["create", "read", "update", "delete"],
  "content_management": ["create", "read", "update"],
  "reports": ["read", "generate"],
  "settings": ["read", "update"]
}

In this structure:

  • The keys (e.g., "user_management") represent different modules or areas of the application.

  • The values are arrays of permitted actions within that module.

This structure allows for granular control over permissions while maintaining flexibility.

Implementing RBAC with Redis

To implement this system with Redis, we'll use Redis hashes to store our user and role data. Here's how we might structure our Redis data:

  1. For Users:

     HSET user:1 id 1 username "john_doe" email "john@example.com" role_id 2
    
  2. For Roles:

     HSET role:2 id 2 name "editor" description "Can edit content" parent_role_id 1 permissions '{"content_management":["create","read","update"],"reports":["read"]}'
    

Checking Permissions

When a user attempts to perform an action, we can check their permissions like this:

  1. Get the user's role ID from Redis

  2. Fetch the role details, including permissions

  3. Check if the required permission exists in the role's permission set

Here's a pseudocode example:

def check_permission(user_id, module, action):
    # Get user's role ID
    role_id = redis.hget(f"user:{user_id}", "role_id")

    # Get role permissions
    role_permissions = json.loads(redis.hget(f"role:{role_id}", "permissions"))

    # Check if the action is allowed
    return action in role_permissions.get(module, [])

# Usage
if check_permission(user_id, "content_management", "update"):
    # Allow the action
else:
    # Deny the action

Conclusion

This RBAC implementation offers a balance of simplicity and power. By using Redis for storage, we ensure fast access to our permission data. The JSON structure for permissions provides flexibility, allowing us to easily add or modify permissions as our application grows.

Remember, while this system is a great starting point, you may need to adapt it to your specific needs. Always consider factors like caching strategies, regular permission updates, and how to handle permission inheritance if you implement a hierarchical role structure.

By implementing RBAC, you're taking a significant step towards securing your application and providing a foundation for scalable user management. Happy coding!

I've created a detailed blog post on implementing Role-Based Access Control (RBAC) in a simple and elegant way. The post includes:

  1. An explanation of RBAC

  2. A simple architecture diagram

  3. Schema examples for users and roles tables

  4. A sample JSON structure for permissions

  5. An explanation of how to implement this using Redis

  6. A pseudocode example of checking permissions

Would you like me to explain or elaborate on any part of this blog post?