fastapi-rbac 0.1.1
FastAPI RBAC (Role-Based Access Control) plugin with comprehensive user and permission management
License: MIT
Requires Python: >=3.11
Keywords: authentication, authorization, fastapi, permissions, rbac

# Fastapi-rbac - Advanced RBAC FastAPI Extension

[![Python Version](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://python.org)
[![FastAPI](https://img.shields.io/badge/FastAPI-0.100%2B-green.svg)](https://fastapi.tiangolo.com)
[![Test Coverage](https://img.shields.io/badge/coverage-89%25-brightgreen.svg)](https://github.com/zxjlm/fastapi-rbac/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

A powerful, production-ready Role-Based Access Control (RBAC) extension for FastAPI applications. Fastapi-rbac provides comprehensive user, role, and permission management with fine-grained access control, dependency injection, and enterprise-grade features.

## 🚀 Key Features

### Core RBAC Functionality

- **Complete Permission Model**: Users → Roles → Permissions with flexible many-to-many relationships
- **Fine-grained Access Control**: Permission-based dependency injection with OR logic support
- **Role Hierarchy**: Support for role inheritance and system/custom role management
- **Soft Delete**: Configurable soft delete for all entities with audit trail

### Advanced Security Features

- **Permission-based Dependencies**: `require_permissions("user:read", "admin:write")` decorator pattern
- **Role-based Dependencies**: Traditional role-based access control support
- **Authentication Middleware**: Pluggable authentication with JWT/session support
- **Security Audit**: Comprehensive audit logging for permission changes

### Developer Experience

- **Plug-and-Play**: Single plugin class integration with minimal configuration
- **Type Safety**: Full SQLModel and Pydantic v2 integration with type hints
- **Auto Documentation**: Automatic OpenAPI/Swagger documentation generation
- **Flexible Configuration**: Environment-based configuration with validation

### Performance & Scalability

- **Optimized Queries**: Single-query permission checking with efficient JOINs
- **Caching Ready**: Built-in cache support for high-performance scenarios
- **Pagination**: Advanced pagination with search and filtering
- **Connection Pooling**: Production-ready database connection management

### Integration & Deployment

- **SSO Integration**: Single Sign-On support with user synchronization
- **Multiple Databases**: Base on SQLModel. MySQL, PostgreSQL, SQLite support
- **Docker Ready**: Container-friendly configuration
- **Production Features**: Health checks, monitoring endpoints, CORS support

## 📋 Requirements

- **Python**: 3.11+
- **Core Dependencies**: FastAPI, SQLModel, Pydantic v2, aiocache, alembic

## 🛠 Installation

### Using pip (Recommended)

```bash
pip install fastapi-rbac
# uv
uv add fastapi-rbac

# !!!!! ATTENTION:
# Due to the database dependency in the project, after updating the project code, it is necessary to use Alembic to generate the database tables and execute them.
```

## 🚀 Quick Start


### ATTENTION

Due to the database dependency in the project, after updating the project code, it is necessary to use `alembic` to generate the database tables and execute them.

### 1. Basic Setup

```python
from fastapi import FastAPI, Depends
from sqlmodel.ext.asyncio.session import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker

from fastapi-rbac import RBACPlugin, RBACConfig

# Create FastAPI app
app = FastAPI(title="My App with RBAC")

# Database setup
database_url = os.getenv("RBAC_DATABASE_URL", "sqlite+aiosqlite:///rbac.db")

SessionLocal = async_sessionmaker(engine, class_=AsyncSession)

async def get_db():
    async with SessionLocal() as session:
        yield session

# Configure RBAC
config = RBACConfig(
    table_prefix="myapp_",
    enable_soft_delete=True,
    cache_ttl=300
)

# Initialize RBAC plugin
rbac = RBACPlugin(config)

# Setup middleware
app.state.rbac_middleware = rbac.get_rbac_middleware()

# Register RBAC routes
rbac_router = rbac.get_router(get_db)
app.include_router(rbac_router, prefix="/api/rbac")
```

### 2. Permission-Based Access Control

```python
from fastapi-rbac import require_permissions

# Protect endpoints with specific permissions
@app.get("/api/users")
async def list_users(
    _: bool = Depends(require_permissions("user:read", "user:list"))
):
    return {"users": []}

@app.post("/api/users")
async def create_user(
    _: bool = Depends(require_permissions("user:create", "admin:all"))
):
    return {"message": "User created"}

# Multiple permission check (OR logic)
@app.get("/api/admin/dashboard")
async def admin_dashboard(
    _: bool = Depends(require_permissions("admin:read", "system:admin"))
):
    return {"dashboard": "data"}
```

### 3. Using Plugin Methods

```python
# Create permission dependencies via plugin
require_user_manage = rbac.get_permission_dependency("user:create", "user:update")

@app.put("/api/users/{user_id}")
async def update_user(
    user_id: int,
    _: bool = Depends(require_user_manage)
):
    return {"message": f"User {user_id} updated"}
```

## examples

### [basic_usage](https://github.com/zxjlm/fastapi-rbac/blob/main/examples/basic_usage.py)

This end-to-end demo boots a fully configured FastAPI application with the RBAC plugin, admin frontend, and seed data. It showcases interactive permission testing via `/index`, complete CRUD dashboards for users/roles/permissions, and built-in redirects/login flows. The script also demonstrates how to initialize the database with sample roles, extend the default `User` model with custom fields, expose health/diagnostic endpoints, and wire permission-protected APIs (`/api/need-user-read-permission`) alongside open endpoints (`/api/free-permission`). Use it as the quickest way to experience the management UI, verify dependency injection behavior, and understand how session-based authentication cooperates with the RBAC middleware.

## Commands

FastAPI RBAC provides two CLI commands to manage RBAC data:

### 1. Initialize Admin Data (`init_data`)

Initialize admin user, role, and permission. This command will:
- Load FastAPI application from the module specified by `--app` parameter
- Ensure database tables are created
- Create admin permission (based on `admin_permission_code` from config)
- Create a role named "admin"
- Create admin user with the specified email
- Bind permission to role, and user to role

**Usage:**
```bash
python -m fastapi_rbac init_data --email admin@example.com --password admin123 --app main:app
```

**Arguments:**
- `--email` (required): Admin user email address
- `--password` (required): Admin user password
- `--app` (required): FastAPI app path in format `module:var` (e.g., `main:app`)

**Examples:**
```bash
# Using default app path
python -m fastapi_rbac init_data --email admin@example.com --password admin123 --app main:app

# Using different app module
python -m fastapi_rbac init_data --email admin@example.com --password admin123 --app app.core:application
```

### 2. Sync Permissions (`sync_permission`)

Extract permission codes from application routes and sync them to the database. This command will:
- Load FastAPI application from the module specified by `--app` parameter
- Extract permission codes from routes using `require_permissions` dependencies
- Add missing permissions to database (incremental sync)
- Leave existing permissions unchanged

**Usage:**
```bash
python -m fastapi_rbac sync_permission --app main:app
```

**Arguments:**
- `--app` (required): FastAPI app path in format `module:var` (e.g., `main:app`)

**Examples:**
```bash
# Sync permissions to database
python -m fastapi_rbac sync_permission --app main:app

# Using different app module
python -m fastapi_rbac sync_permission --app app.core:application
```

**Notes:**
- Ensure FastAPI application is constructed at module level (not only in `main()` function)
- Ensure `RBACPlugin(app, RBACConfig(...))` is instantiated during module import
- Ensure `RBACConfig.custom_session_maker` is set (e.g., `gen_rbac_async_session`)

## ⚙️ Configuration

### Environment Variables

```bash
# Database Configuration
DATABASE_URL=mysql+aiomysql://user:pass@localhost:3306/rbac_db

# RBAC Plugin Configuration
RBAC_TABLE_PREFIX=rbac_
RBAC_ENABLE_SOFT_DELETE=true
RBAC_CACHE_TTL=300
RBAC_DEFAULT_PAGE_SIZE=20
RBAC_MAX_PAGE_SIZE=100

# Security Configuration
RBAC_ENABLE_AUDIT_LOG=true
RBAC_SSO_ENABLED=true
RBAC_SSO_USER_SYNC=true

# Performance Configuration
RBAC_ENABLE_CACHE=false
RBAC_ENABLE_ROLE_HIERARCHY=false
```

### Programmatic Configuration

```python
from fastapi-rbac import RBACConfig

config = RBACConfig(
    # Database settings
    table_prefix="myapp_rbac_",
    enable_soft_delete=True,
    
    # Caching settings  
    cache_ttl=600,
    enable_cache=True,
    
    # Pagination settings
    default_page_size=25,
    max_page_size=200,
    
    # Security settings
    enable_audit_log=True,
    role_assignment_audit=True,
    
    # SSO integration
    sso_enabled=True,
    sso_user_sync=True,
    
    # System roles
    system_roles=["Super Admin", "Admin", "User"],
    default_user_role="User"
)
```

## 🔐 Authentication Integration

### Custom Authentication

```python
from fastapi import Request
from fastapi-rbac import RBACMiddleware

class CustomRBACMiddleware(RBACMiddleware):
    async def get_current_user_id(self, request: Request) -> Optional[int]:
        # JWT token example
        token = request.headers.get("Authorization")
        if token and token.startswith("Bearer "):
            try:
                payload = jwt.decode(token.split(" ")[1], SECRET_KEY, algorithms=["HS256"])
                return payload.get("user_id")
            except jwt.InvalidTokenError:
                return None
        return None

# Use custom middleware
app.state.rbac_middleware = CustomRBACMiddleware(rbac)
```

### SSO Integration

```python
@app.post("/api/auth/sso-sync")
async def sync_user_from_sso(
    sso_user_data: dict,
    db_session: AsyncSession = Depends(get_db)
):
    user_serializer = rbac.get_user_serializer(db_session)
    
    # Sync user from external SSO
    user = await user_serializer.create_or_update_user({
        "external_id": sso_user_data["id"],
        "name": sso_user_data["name"],
        "email": sso_user_data["email"]
    })
    
    return {"user_id": user.id, "synced": True}
```

## 🧪 Testing

### Run Tests

```bash
# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=. --cov-report=html

# Run specific test files
uv run pytest tests/test_permission_dependencies.py -v
```

### Test Data Setup

```python
import pytest
from sqlmodel.ext.asyncio.session import AsyncSession
from fastapi-rbac import RBACPlugin

@pytest.fixture
async def setup_rbac_data(db_session: AsyncSession):
    rbac = RBACPlugin()
    
    # Create test user
    user_serializer = rbac.get_user_serializer(db_session)
    user = await user_serializer.create_user({
        "name": "Test User",
        "email": "test@example.com"
    })
    
    # Create test role with permissions
    role_serializer = rbac.get_role_serializer(db_session)
    role = await role_serializer.create_role({
        "name": "Test Role",
        "description": "Test role with permissions"
    })
    
    return {"user": user, "role": role}
```

## 🚀 Production Deployment

### Docker Deployment

```dockerfile
FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .
EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```

### docker-compose.yml

```yaml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=mysql+aiomysql://user:pass@db:3306/rbac_db
      - RBAC_ENABLE_CACHE=true
      - RBAC_CACHE_TTL=600
    depends_on:
      - db
      
  db:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=rbac_db
    volumes:
      - mysql_data:/var/lib/mysql

volumes:
  mysql_data:
```

### Performance Tuning

```python
# Production configuration example
config = RBACConfig(
    # Enable caching for better performance
    enable_cache=True,
    cache_ttl=900,  # 15 minutes
    
    # Optimize pagination
    default_page_size=50,
    max_page_size=500,
    
    # Database optimization
    pool_size=20,
    max_overflow=30,
    pool_timeout=30,
    
    # Security hardening
    enable_audit_log=True,
    role_assignment_audit=True
)
```

## 📖 Examples

Check the [examples/](examples/) directory for comprehensive integration examples:

- **[basic_usage.py](examples/basic_usage.py)**: Simple integration for prototyping
- **[advanced_integration.py](examples/advanced_integration.py)**: Production-ready setup with middleware
- **[permission_dependency_example.py](examples/permission_dependency_example.py)**: Permission-based access control

## 🤝 Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.

### Development Setup

```bash
# Clone the repository
git clone https://github.com/zxjlm/fastapi-rbac.git
cd fastapi-rbac

# Install development dependencies
uv install --dev

# Install pre-commit hooks
pre-commit install

# Run tests
uv run pytest

# Run linting
uv run ruff check .
uv run ruff format .
```

## 📄 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## 🙏 Acknowledgments

- Built with [FastAPI](https://fastapi.tiangolo.com/) and [SQLModel](https://sqlmodel.tiangolo.com/)
- Inspired by enterprise RBAC best practices
- Thanks to all contributors and the open-source community

## TODO: How to get user_info?

base on request.

## TODO: How to get permission in project?

init via script.

## 📞 Support

- **Documentation**: TBD
- **Issues**: [GitHub Issues](https://github.com/zxjlm/fastapi-rbac/issues)
- **Email**: <zxjlm233@gmail.com>