permissions2fast-fastapi 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- permissions2fast_fastapi-0.1.0/LICENSE +21 -0
- permissions2fast_fastapi-0.1.0/PKG-INFO +141 -0
- permissions2fast_fastapi-0.1.0/README.md +87 -0
- permissions2fast_fastapi-0.1.0/pyproject.toml +68 -0
- permissions2fast_fastapi-0.1.0/setup.cfg +4 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/__init__.py +26 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/__version__.py +1 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/dependencies.py +123 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/__init__.py +21 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/permission_assignment_model.py +13 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/permission_category_model.py +18 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/permission_model.py +17 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/permission_route_model.py +13 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/role_model.py +21 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/route_model.py +14 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/tenant_model.py +16 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/user_role_model.py +12 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/user_tenant_role_model.py +15 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/routers/__init__.py +5 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/routers/permissions_router.py +191 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/routers/roles_router.py +177 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/routers/routes_router.py +44 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/schemas/__init__.py +53 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/schemas/permission_category_schema.py +10 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/schemas/permission_schema.py +35 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/schemas/role_schema.py +40 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/schemas/route_schema.py +11 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/services/__init__.py +6 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/services/access_service.py +110 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/services/permission_service.py +197 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/services/role_service.py +256 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/services/route_service.py +44 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/settings.py +64 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/utils/__init__.py +27 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/utils/permission_cache.py +251 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/utils/redis_client.py +82 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi.egg-info/PKG-INFO +141 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi.egg-info/SOURCES.txt +43 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi.egg-info/dependency_links.txt +1 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi.egg-info/requires.txt +9 -0
- permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi.egg-info/top_level.txt +1 -0
- permissions2fast_fastapi-0.1.0/tests/test_models.py +130 -0
- permissions2fast_fastapi-0.1.0/tests/test_multitenancy_config.py +34 -0
- permissions2fast_fastapi-0.1.0/tests/test_multitenancy_rbac.py +123 -0
- permissions2fast_fastapi-0.1.0/tests/test_permissions.py +153 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Angel Daniel Sanchez Castillo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: permissions2fast-fastapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Role-based access control (RBAC) and permission management extension for oauth2fast-fastapi
|
|
5
|
+
Author-email: Angel Daniel Sanchez Castillo <angeldaniel.sanchezcastillo@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Angel Daniel Sanchez Castillo
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/AngelDanielSanchezCastillo/permissions2fast-fastapi
|
|
29
|
+
Project-URL: Repository, https://github.com/AngelDanielSanchezCastillo/permissions2fast-fastapi
|
|
30
|
+
Project-URL: Issues, https://github.com/AngelDanielSanchezCastillo/permissions2fast-fastapi/issues
|
|
31
|
+
Keywords: fastapi,permissions,rbac,oauth2,authorization,sqlmodel
|
|
32
|
+
Classifier: Development Status :: 3 - Alpha
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
39
|
+
Classifier: Framework :: FastAPI
|
|
40
|
+
Classifier: Topic :: Security
|
|
41
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
42
|
+
Requires-Python: >=3.10
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
License-File: LICENSE
|
|
45
|
+
Requires-Dist: oauth2fast-fastapi>=0.2.2
|
|
46
|
+
Provides-Extra: dev
|
|
47
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
48
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
49
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
50
|
+
Requires-Dist: httpx>=0.24.0; extra == "dev"
|
|
51
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
52
|
+
Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
|
|
53
|
+
Dynamic: license-file
|
|
54
|
+
|
|
55
|
+
# permissions2fast-fastapi
|
|
56
|
+
|
|
57
|
+
🔒 Role-Based Access Control (RBAC) extension for `oauth2fast-fastapi`.
|
|
58
|
+
|
|
59
|
+
Easily manage user roles and permissions in your FastAPI application with support for Multi-Tenancy and High-Performance Redis Caching.
|
|
60
|
+
|
|
61
|
+
## Features
|
|
62
|
+
|
|
63
|
+
- 👥 **Role Management**: Create, assign, and manage roles for users.
|
|
64
|
+
- 🔑 **Granular Permissions**: Define specific permissions and assign them to roles or directly to users (polymorphic assignments).
|
|
65
|
+
- 🏢 **Multi-Tenancy (Optional)**: Isolate roles and permissions per tenant context.
|
|
66
|
+
- � **Redis Caching (Optional)**: High-performance permission evaluation using Redis to minimize database lookups.
|
|
67
|
+
- �🛡️ **Route Protection**: Dependencies to protect endpoints based on roles or permissions.
|
|
68
|
+
- ⚡ **Async Support**: Fully async database interactions via `pgsqlasync2fast-fastapi`.
|
|
69
|
+
- 🔌 **Seamless Integration**: Built to extend `oauth2fast-fastapi`.
|
|
70
|
+
|
|
71
|
+
## Installation
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install permissions2fast-fastapi
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
This package uses the same database connection logic as `oauth2fast-fastapi`. Configure your environment variables in `.env`.
|
|
80
|
+
|
|
81
|
+
### Basic Settings
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Database Configuration
|
|
85
|
+
DB_CONNECTIONS__AUTH__USERNAME=db_user
|
|
86
|
+
DB_CONNECTIONS__AUTH__PASSWORD=db_password
|
|
87
|
+
DB_CONNECTIONS__AUTH__HOST=localhost
|
|
88
|
+
DB_CONNECTIONS__AUTH__DATABASE=db_name
|
|
89
|
+
DB_CONNECTIONS__AUTH__PORT=5432
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Advanced Features (Multi-Tenancy & Redis)
|
|
93
|
+
|
|
94
|
+
You can enable multi-tenancy and Redis caching by setting the following environment variables:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
PERMISSIONS_ENABLE_TENANCY=True
|
|
98
|
+
PERMISSIONS_REDIS_RBAC_ENABLED=True
|
|
99
|
+
|
|
100
|
+
# Redis connection details (if caching is enabled)
|
|
101
|
+
PERMISSIONS_REDIS__HOST=localhost
|
|
102
|
+
PERMISSIONS_REDIS__PORT=6379
|
|
103
|
+
PERMISSIONS_REDIS__DB=0
|
|
104
|
+
# PERMISSIONS_REDIS__PASSWORD=your_redis_password
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Usage
|
|
108
|
+
|
|
109
|
+
### 1. Basic Integration
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from fastapi import FastAPI
|
|
113
|
+
from permissions2fast_fastapi import permissions_router, roles_router
|
|
114
|
+
from oauth2fast_fastapi import router as auth_router
|
|
115
|
+
|
|
116
|
+
app = FastAPI()
|
|
117
|
+
|
|
118
|
+
app.include_router(auth_router)
|
|
119
|
+
app.include_router(permissions_router)
|
|
120
|
+
app.include_router(roles_router)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 2. Protecting Routes
|
|
124
|
+
|
|
125
|
+
Use the provided dependencies to restrict access to endpoints. The system will automatically check Redis cache if enabled, and fallback to database queries if needed. Tenant context is automatically respected if Tenancy is enabled and a Tenant ID is injected in the request context.
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from fastapi import Depends
|
|
129
|
+
from permissions2fast_fastapi.dependencies import has_permission, has_role
|
|
130
|
+
from oauth2fast_fastapi.models import User
|
|
131
|
+
|
|
132
|
+
# Require a specific role
|
|
133
|
+
@app.get("/admin-dashboard")
|
|
134
|
+
async def admin_dashboard(user: User = Depends(has_role("admin"))):
|
|
135
|
+
return {"message": "Welcome Admin"}
|
|
136
|
+
|
|
137
|
+
# Require a specific permission
|
|
138
|
+
@app.get("/edit-post")
|
|
139
|
+
async def edit_post(user: User = Depends(has_permission("posts.edit"))):
|
|
140
|
+
return {"message": "You can edit posts"}
|
|
141
|
+
```
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# permissions2fast-fastapi
|
|
2
|
+
|
|
3
|
+
🔒 Role-Based Access Control (RBAC) extension for `oauth2fast-fastapi`.
|
|
4
|
+
|
|
5
|
+
Easily manage user roles and permissions in your FastAPI application with support for Multi-Tenancy and High-Performance Redis Caching.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 👥 **Role Management**: Create, assign, and manage roles for users.
|
|
10
|
+
- 🔑 **Granular Permissions**: Define specific permissions and assign them to roles or directly to users (polymorphic assignments).
|
|
11
|
+
- 🏢 **Multi-Tenancy (Optional)**: Isolate roles and permissions per tenant context.
|
|
12
|
+
- � **Redis Caching (Optional)**: High-performance permission evaluation using Redis to minimize database lookups.
|
|
13
|
+
- �🛡️ **Route Protection**: Dependencies to protect endpoints based on roles or permissions.
|
|
14
|
+
- ⚡ **Async Support**: Fully async database interactions via `pgsqlasync2fast-fastapi`.
|
|
15
|
+
- 🔌 **Seamless Integration**: Built to extend `oauth2fast-fastapi`.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install permissions2fast-fastapi
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Configuration
|
|
24
|
+
|
|
25
|
+
This package uses the same database connection logic as `oauth2fast-fastapi`. Configure your environment variables in `.env`.
|
|
26
|
+
|
|
27
|
+
### Basic Settings
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Database Configuration
|
|
31
|
+
DB_CONNECTIONS__AUTH__USERNAME=db_user
|
|
32
|
+
DB_CONNECTIONS__AUTH__PASSWORD=db_password
|
|
33
|
+
DB_CONNECTIONS__AUTH__HOST=localhost
|
|
34
|
+
DB_CONNECTIONS__AUTH__DATABASE=db_name
|
|
35
|
+
DB_CONNECTIONS__AUTH__PORT=5432
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Advanced Features (Multi-Tenancy & Redis)
|
|
39
|
+
|
|
40
|
+
You can enable multi-tenancy and Redis caching by setting the following environment variables:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
PERMISSIONS_ENABLE_TENANCY=True
|
|
44
|
+
PERMISSIONS_REDIS_RBAC_ENABLED=True
|
|
45
|
+
|
|
46
|
+
# Redis connection details (if caching is enabled)
|
|
47
|
+
PERMISSIONS_REDIS__HOST=localhost
|
|
48
|
+
PERMISSIONS_REDIS__PORT=6379
|
|
49
|
+
PERMISSIONS_REDIS__DB=0
|
|
50
|
+
# PERMISSIONS_REDIS__PASSWORD=your_redis_password
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
### 1. Basic Integration
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from fastapi import FastAPI
|
|
59
|
+
from permissions2fast_fastapi import permissions_router, roles_router
|
|
60
|
+
from oauth2fast_fastapi import router as auth_router
|
|
61
|
+
|
|
62
|
+
app = FastAPI()
|
|
63
|
+
|
|
64
|
+
app.include_router(auth_router)
|
|
65
|
+
app.include_router(permissions_router)
|
|
66
|
+
app.include_router(roles_router)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 2. Protecting Routes
|
|
70
|
+
|
|
71
|
+
Use the provided dependencies to restrict access to endpoints. The system will automatically check Redis cache if enabled, and fallback to database queries if needed. Tenant context is automatically respected if Tenancy is enabled and a Tenant ID is injected in the request context.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from fastapi import Depends
|
|
75
|
+
from permissions2fast_fastapi.dependencies import has_permission, has_role
|
|
76
|
+
from oauth2fast_fastapi.models import User
|
|
77
|
+
|
|
78
|
+
# Require a specific role
|
|
79
|
+
@app.get("/admin-dashboard")
|
|
80
|
+
async def admin_dashboard(user: User = Depends(has_role("admin"))):
|
|
81
|
+
return {"message": "Welcome Admin"}
|
|
82
|
+
|
|
83
|
+
# Require a specific permission
|
|
84
|
+
@app.get("/edit-post")
|
|
85
|
+
async def edit_post(user: User = Depends(has_permission("posts.edit"))):
|
|
86
|
+
return {"message": "You can edit posts"}
|
|
87
|
+
```
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "permissions2fast-fastapi"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Role-based access control (RBAC) and permission management extension for oauth2fast-fastapi"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = {file = "LICENSE"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Angel Daniel Sanchez Castillo", email = "angeldaniel.sanchezcastillo@gmail.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["fastapi", "permissions", "rbac", "oauth2", "authorization", "sqlmodel"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Framework :: FastAPI",
|
|
25
|
+
"Topic :: Security",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
dependencies = [
|
|
30
|
+
"oauth2fast-fastapi>=0.2.2",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
dev = [
|
|
35
|
+
"pytest>=7.0.0",
|
|
36
|
+
"pytest-asyncio>=0.21.0",
|
|
37
|
+
"pytest-cov>=4.0.0",
|
|
38
|
+
"httpx>=0.24.0",
|
|
39
|
+
"mypy>=1.0.0",
|
|
40
|
+
"python-dotenv>=1.0.0",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://github.com/AngelDanielSanchezCastillo/permissions2fast-fastapi"
|
|
45
|
+
Repository = "https://github.com/AngelDanielSanchezCastillo/permissions2fast-fastapi"
|
|
46
|
+
Issues = "https://github.com/AngelDanielSanchezCastillo/permissions2fast-fastapi/issues"
|
|
47
|
+
|
|
48
|
+
[tool.setuptools]
|
|
49
|
+
package-dir = {"" = "src"}
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.packages.find]
|
|
52
|
+
where = ["src"]
|
|
53
|
+
include = ["permissions2fast_fastapi*"]
|
|
54
|
+
|
|
55
|
+
[tool.pytest.ini_options]
|
|
56
|
+
testpaths = ["tests"]
|
|
57
|
+
python_files = ["test_*.py"]
|
|
58
|
+
python_classes = ["Test*"]
|
|
59
|
+
python_functions = ["test_*"]
|
|
60
|
+
asyncio_mode = "auto"
|
|
61
|
+
asyncio_default_fixture_loop_scope = "session"
|
|
62
|
+
asyncio_default_test_loop_scope = "session"
|
|
63
|
+
|
|
64
|
+
[tool.mypy]
|
|
65
|
+
python_version = "3.10"
|
|
66
|
+
warn_return_any = true
|
|
67
|
+
warn_unused_configs = true
|
|
68
|
+
disallow_untyped_defs = false
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
permissions2fast-fastapi
|
|
3
|
+
|
|
4
|
+
Complete RBAC (Role-Based Access Control) system for FastAPI applications.
|
|
5
|
+
Provides role management, permission checking, and user-role assignments.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
9
|
+
|
|
10
|
+
from .models.role_model import Role
|
|
11
|
+
from .models.permission_model import Permission
|
|
12
|
+
from .models.permission_category_model import PermissionCategory
|
|
13
|
+
from .models.route_model import Route
|
|
14
|
+
from .models.user_role_model import UserRole
|
|
15
|
+
from .models.permission_assignment_model import PermissionAssignment
|
|
16
|
+
from .models.permission_route_model import PermissionRoute
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"Role",
|
|
20
|
+
"Permission",
|
|
21
|
+
"PermissionCategory",
|
|
22
|
+
"Route",
|
|
23
|
+
"UserRole",
|
|
24
|
+
"PermissionAssignment",
|
|
25
|
+
"PermissionRoute",
|
|
26
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FastAPI Dependencies
|
|
3
|
+
|
|
4
|
+
Dependencies for protecting routes based on roles and permissions.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
from fastapi import Depends, HTTPException, Request, status
|
|
10
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
11
|
+
|
|
12
|
+
# Import from oauth2fast-fastapi directly
|
|
13
|
+
from oauth2fast_fastapi.dependencies import get_current_verified_user, get_auth_session
|
|
14
|
+
from oauth2fast_fastapi import User
|
|
15
|
+
|
|
16
|
+
from .services import access_service, role_service
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def has_role(
|
|
20
|
+
role_name: str,
|
|
21
|
+
):
|
|
22
|
+
"""
|
|
23
|
+
Dependency to require a specific role.
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
@app.get("/admin")
|
|
27
|
+
def admin_route(user: User = Depends(has_role("admin"))):
|
|
28
|
+
...
|
|
29
|
+
"""
|
|
30
|
+
async def _has_role(
|
|
31
|
+
request: Request,
|
|
32
|
+
user: Annotated[User, Depends(get_current_verified_user)],
|
|
33
|
+
session: Annotated[AsyncSession, Depends(get_auth_session)],
|
|
34
|
+
) -> User:
|
|
35
|
+
tenant_id = get_tenant_id(request)
|
|
36
|
+
user_roles = await role_service.list_user_roles(user.id, session, tenant_id=tenant_id)
|
|
37
|
+
|
|
38
|
+
has_required = any(r.name == role_name for r in user_roles)
|
|
39
|
+
|
|
40
|
+
if not has_required:
|
|
41
|
+
raise HTTPException(
|
|
42
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
43
|
+
detail=f"Missing required role: {role_name}",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return user
|
|
47
|
+
|
|
48
|
+
return _has_role
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_tenant_id(request: Request) -> int | None:
|
|
52
|
+
"""
|
|
53
|
+
Extract tenant_id from request.
|
|
54
|
+
Priority:
|
|
55
|
+
1. request.state.tenant_id (injected by external middleware)
|
|
56
|
+
2. X-Tenant-ID header
|
|
57
|
+
"""
|
|
58
|
+
from .settings import settings
|
|
59
|
+
if not settings.enable_tenancy:
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
# First check state (injected by middleware)
|
|
63
|
+
if hasattr(request.state, "tenant_id") and request.state.tenant_id:
|
|
64
|
+
try:
|
|
65
|
+
return int(request.state.tenant_id)
|
|
66
|
+
except ValueError:
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
# Fallback to header
|
|
70
|
+
header_tenant = request.headers.get("X-Tenant-ID")
|
|
71
|
+
if header_tenant:
|
|
72
|
+
try:
|
|
73
|
+
return int(header_tenant)
|
|
74
|
+
except ValueError:
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def has_permission(
|
|
81
|
+
permission_route: str | None = None,
|
|
82
|
+
method: str | None = None,
|
|
83
|
+
):
|
|
84
|
+
"""
|
|
85
|
+
Dependency to require permission for a route.
|
|
86
|
+
|
|
87
|
+
If params are None, verifies access to the *current* request path and method.
|
|
88
|
+
|
|
89
|
+
Usage:
|
|
90
|
+
@app.get("/items")
|
|
91
|
+
def items(user: User = Depends(has_permission())):
|
|
92
|
+
# Checks if user can GET /items
|
|
93
|
+
...
|
|
94
|
+
|
|
95
|
+
@app.get("/items")
|
|
96
|
+
def items(user: User = Depends(has_permission(permission_route="/api/items", method="GET"))):
|
|
97
|
+
...
|
|
98
|
+
"""
|
|
99
|
+
async def _has_permission(
|
|
100
|
+
request: Request,
|
|
101
|
+
user: Annotated[User, Depends(get_current_verified_user)],
|
|
102
|
+
session: Annotated[AsyncSession, Depends(get_auth_session)],
|
|
103
|
+
) -> User:
|
|
104
|
+
# Determine what to check
|
|
105
|
+
route_to_check = permission_route or request.url.path
|
|
106
|
+
method_to_check = method or request.method
|
|
107
|
+
|
|
108
|
+
# Extract tenant context
|
|
109
|
+
tenant_id = get_tenant_id(request)
|
|
110
|
+
|
|
111
|
+
is_allowed = await access_service.check_user_access(
|
|
112
|
+
user.id, route_to_check, method_to_check, session, tenant_id=tenant_id
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if not is_allowed:
|
|
116
|
+
raise HTTPException(
|
|
117
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
118
|
+
detail="Not enough permissions to access this resource",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
return user
|
|
122
|
+
|
|
123
|
+
return _has_permission
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .role_model import Role
|
|
2
|
+
from .permission_model import Permission
|
|
3
|
+
from .permission_category_model import PermissionCategory
|
|
4
|
+
from .route_model import Route
|
|
5
|
+
from .user_role_model import UserRole
|
|
6
|
+
from .permission_assignment_model import PermissionAssignment
|
|
7
|
+
from .permission_route_model import PermissionRoute
|
|
8
|
+
from .tenant_model import Tenant
|
|
9
|
+
from .user_tenant_role_model import UserTenantRole
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"Role",
|
|
13
|
+
"Permission",
|
|
14
|
+
"PermissionCategory",
|
|
15
|
+
"Route",
|
|
16
|
+
"UserRole",
|
|
17
|
+
"PermissionAssignment",
|
|
18
|
+
"PermissionRoute",
|
|
19
|
+
"Tenant",
|
|
20
|
+
"UserTenantRole",
|
|
21
|
+
]
|
permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/permission_assignment_model.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from sqlmodel import Field, SQLModel
|
|
2
|
+
from oauth2fast_fastapi.models import AuthModel
|
|
3
|
+
|
|
4
|
+
class PermissionAssignment(AuthModel, table=True):
|
|
5
|
+
"""
|
|
6
|
+
Polymorphic Permission Assignment for RBAC.
|
|
7
|
+
Description: Assigns a permission directly to an entity (e.g. User or Role).
|
|
8
|
+
"""
|
|
9
|
+
__tablename__ = "permission_assignments"
|
|
10
|
+
|
|
11
|
+
permission_id: int = Field(primary_key=True, foreign_key="permissions.id")
|
|
12
|
+
entity_type: str = Field(primary_key=True, index=True) # e.g., "User", "Team"
|
|
13
|
+
entity_id: int = Field(primary_key=True, index=True)
|
permissions2fast_fastapi-0.1.0/src/permissions2fast_fastapi/models/permission_category_model.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from sqlmodel import Field, SQLModel, Relationship
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
|
|
4
|
+
# Forward reference for relationship
|
|
5
|
+
from oauth2fast_fastapi.models import AuthModel
|
|
6
|
+
|
|
7
|
+
class PermissionCategory(AuthModel, table=True):
|
|
8
|
+
"""
|
|
9
|
+
Permission Category definition for RBAC.
|
|
10
|
+
Description: Groups related permissions together.
|
|
11
|
+
"""
|
|
12
|
+
__tablename__ = "permission_categories"
|
|
13
|
+
|
|
14
|
+
id: Optional[int] = Field(default=None, primary_key=True)
|
|
15
|
+
name: str = Field(index=True, unique=True)
|
|
16
|
+
|
|
17
|
+
# Relationships
|
|
18
|
+
# permissions: List["Permission"] = Relationship(back_populates="category")
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from sqlmodel import Field, SQLModel, Relationship
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from oauth2fast_fastapi.models import AuthModel
|
|
4
|
+
|
|
5
|
+
class Permission(AuthModel, table=True):
|
|
6
|
+
"""
|
|
7
|
+
Permission definition for RBAC.
|
|
8
|
+
Description: Represents a specific action or access right.
|
|
9
|
+
"""
|
|
10
|
+
__tablename__ = "permissions"
|
|
11
|
+
|
|
12
|
+
id: Optional[int] = Field(default=None, primary_key=True)
|
|
13
|
+
name: str = Field(index=True, unique=True)
|
|
14
|
+
permission_category_id: int = Field(foreign_key="permission_categories.id")
|
|
15
|
+
|
|
16
|
+
# Relationships
|
|
17
|
+
# category: "PermissionCategory" = Relationship(back_populates="permissions")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from sqlmodel import Field, SQLModel
|
|
2
|
+
from oauth2fast_fastapi.models import AuthModel
|
|
3
|
+
|
|
4
|
+
class PermissionRoute(AuthModel, table=True):
|
|
5
|
+
"""
|
|
6
|
+
Permission Route mapping for RBAC.
|
|
7
|
+
Description: Maps permissions to specific API routes.
|
|
8
|
+
"""
|
|
9
|
+
__tablename__ = "permission_routes"
|
|
10
|
+
|
|
11
|
+
id: int | None = Field(default=None, primary_key=True)
|
|
12
|
+
permission_id: int = Field(foreign_key="permissions.id")
|
|
13
|
+
route_id: int = Field(foreign_key="routes.id")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from sqlmodel import BigInteger, Column, Field
|
|
2
|
+
from sqlmodel import BigInteger, Column, Field, SQLModel
|
|
3
|
+
|
|
4
|
+
from oauth2fast_fastapi.models import AuthModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Role(AuthModel, table=True):
|
|
8
|
+
"""
|
|
9
|
+
Role definition for RBAC.
|
|
10
|
+
Description: Role model
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__tablename__ = "roles"
|
|
14
|
+
|
|
15
|
+
id: int = Field(
|
|
16
|
+
default=None, sa_column=Column(BigInteger, index=True, primary_key=True)
|
|
17
|
+
)
|
|
18
|
+
name: str = Field(index=True, unique=True)
|
|
19
|
+
description: str | None = Field(default=None)
|
|
20
|
+
is_active: bool = Field(default=True)
|
|
21
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from sqlmodel import Field, SQLModel
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from oauth2fast_fastapi.models import AuthModel
|
|
4
|
+
|
|
5
|
+
class Route(AuthModel, table=True):
|
|
6
|
+
"""
|
|
7
|
+
Route definition for RBAC.
|
|
8
|
+
Description: Represents an API endpoint or accessible resource path.
|
|
9
|
+
"""
|
|
10
|
+
__tablename__ = "routes"
|
|
11
|
+
|
|
12
|
+
id: Optional[int] = Field(default=None, primary_key=True)
|
|
13
|
+
name: str = Field(index=True, unique=True) # The path
|
|
14
|
+
is_active: bool = Field(default=True)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from sqlmodel import Field, SQLModel
|
|
2
|
+
from oauth2fast_fastapi.models import AuthModel
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Tenant(AuthModel, table=True):
|
|
6
|
+
"""
|
|
7
|
+
Tenant definition for Multi-tenant RBAC.
|
|
8
|
+
Description: Represents an isolated organization or tenant.
|
|
9
|
+
"""
|
|
10
|
+
__tablename__ = "tenants"
|
|
11
|
+
|
|
12
|
+
id: int | None = Field(default=None, primary_key=True)
|
|
13
|
+
name: str = Field(index=True)
|
|
14
|
+
schema_name: str | None = Field(default=None, description="DB Schema name if applicable")
|
|
15
|
+
db_url: str | None = Field(default=None, description="External DB URL if applicable")
|
|
16
|
+
is_active: bool = Field(default=True)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from sqlmodel import Field, SQLModel
|
|
2
|
+
from oauth2fast_fastapi.models import AuthModel
|
|
3
|
+
|
|
4
|
+
class UserRole(AuthModel, table=True):
|
|
5
|
+
"""
|
|
6
|
+
User Role mapping for RBAC.
|
|
7
|
+
Description: Maps users to their assigned roles.
|
|
8
|
+
"""
|
|
9
|
+
__tablename__ = "user_role"
|
|
10
|
+
|
|
11
|
+
role_id: int = Field(primary_key=True, foreign_key="roles.id")
|
|
12
|
+
user_id: int = Field(primary_key=True, index=True, foreign_key="users.id")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from sqlmodel import Field, SQLModel
|
|
2
|
+
from oauth2fast_fastapi.models import AuthModel
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class UserTenantRole(AuthModel, table=True):
|
|
6
|
+
"""
|
|
7
|
+
Tenant-specific Role mapping for RBAC.
|
|
8
|
+
Description: Maps users to roles within a specific tenant context.
|
|
9
|
+
"""
|
|
10
|
+
__tablename__ = "user_tenant_roles"
|
|
11
|
+
|
|
12
|
+
id: int | None = Field(default=None, primary_key=True)
|
|
13
|
+
user_id: int = Field(index=True, foreign_key="users.id")
|
|
14
|
+
tenant_id: int = Field(foreign_key="tenants.id", index=True)
|
|
15
|
+
role_id: int = Field(foreign_key="roles.id", index=True)
|