abs-auth-rbac-core 0.2.1__tar.gz → 0.2.3__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.
Potentially problematic release.
This version of abs-auth-rbac-core might be problematic. Click here for more details.
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/PKG-INFO +286 -324
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/README.md +282 -321
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/rbac/service.py +63 -49
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/util/permission_constants.py +50 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/pyproject.toml +3 -3
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/__init__.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/auth/__init__.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/auth/auth_functions.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/auth/jwt_functions.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/auth/middleware.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/__init__.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/base_model.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/gov_casbin_rule.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/permissions.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/rbac_model.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/role_permission.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/roles.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/seeder/permission_seeder.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/user.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/user_permission.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/models/user_role.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/rbac/__init__.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/rbac/decorator.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/rbac/policy.conf +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/schema/__init__.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/schema/permission.py +0 -0
- {abs_auth_rbac_core-0.2.1 → abs_auth_rbac_core-0.2.3}/abs_auth_rbac_core/util/__init__.py +0 -0
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: abs-auth-rbac-core
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: RBAC and Auth core utilities including JWT token management.
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: AutoBridgeSystems
|
|
7
7
|
Author-email: info@autobridgesystems.com
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.12,<4.0
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
12
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
-
Requires-Dist: abs-exception-core (>=0.1.
|
|
13
|
+
Requires-Dist: abs-exception-core (>=0.1.4,<0.2.0)
|
|
13
14
|
Requires-Dist: casbin (>=1.41.0,<2.0.0)
|
|
14
15
|
Requires-Dist: casbin-redis-watcher (>=1.3.0,<2.0.0)
|
|
15
16
|
Requires-Dist: casbin-sqlalchemy-adapter (>=1.4.0,<2.0.0)
|
|
@@ -24,30 +25,55 @@ Description-Content-Type: text/markdown
|
|
|
24
25
|
|
|
25
26
|
A comprehensive authentication and Role-Based Access Control (RBAC) package for FastAPI applications. This package provides robust JWT-based authentication and flexible role-based permission management using Casbin with Redis support for real-time policy updates.
|
|
26
27
|
|
|
27
|
-
## Features
|
|
28
|
+
## 🚀 Features
|
|
28
29
|
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
30
|
+
- **🔐 JWT-based Authentication**: Secure token-based authentication with customizable expiration
|
|
31
|
+
- **🔒 Password Security**: Secure password storage using bcrypt with passlib
|
|
32
|
+
- **👥 Role-Based Access Control (RBAC)**: Flexible permission management using Casbin
|
|
33
|
+
- **⚡ Real-time Policy Updates**: Redis integration for live policy synchronization
|
|
34
|
+
- **🔄 User-Role Management**: Dynamic role assignment and revocation
|
|
35
|
+
- **🛡️ Permission Enforcement**: Decorator-based permission checking
|
|
36
|
+
- **🔌 Middleware Integration**: Seamless FastAPI middleware integration
|
|
37
|
+
- **📝 Comprehensive Error Handling**: Built-in exception handling for security scenarios
|
|
38
|
+
- **🏗️ Dependency Injection Ready**: Compatible with dependency-injector
|
|
39
|
+
- **📊 Permission Constants**: Predefined permission constants and enums
|
|
37
40
|
|
|
38
|
-
## Installation
|
|
41
|
+
## 📦 Installation
|
|
39
42
|
|
|
40
43
|
```bash
|
|
41
44
|
pip install abs-auth-rbac-core
|
|
42
45
|
```
|
|
43
46
|
|
|
44
|
-
##
|
|
47
|
+
## 🏗️ Architecture Overview
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
51
|
+
│ FastAPI App │ │ Auth Middleware│ │ RBAC Service │
|
|
52
|
+
│ │ │ │ │ │
|
|
53
|
+
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
|
|
54
|
+
│ │ Routes │ │◄──►│ │JWT Validation│ │◄──►│ │Permission │ │
|
|
55
|
+
│ │ │ │ │ │User Fetch │ │ │ │Checking │ │
|
|
56
|
+
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
|
|
57
|
+
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
58
|
+
│ │ │
|
|
59
|
+
│ │ │
|
|
60
|
+
▼ ▼ ▼
|
|
61
|
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
62
|
+
│ Database │ │ Redis │ │ Casbin │
|
|
63
|
+
│ (Users, │ │ (Policy │ │ (Policy │
|
|
64
|
+
│ Roles, │ │ Updates) │ │ Engine) │
|
|
65
|
+
│ Permissions) │ │ │ │ │
|
|
66
|
+
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 🚀 Quick Start
|
|
45
70
|
|
|
46
71
|
### 1. Basic Setup
|
|
47
72
|
|
|
48
73
|
```python
|
|
49
74
|
from abs_auth_rbac_core.auth.jwt_functions import JWTFunctions
|
|
50
75
|
from abs_auth_rbac_core.rbac import RBACService
|
|
76
|
+
from abs_auth_rbac_core.schema.permission import RedisWatcherSchema
|
|
51
77
|
import os
|
|
52
78
|
|
|
53
79
|
# Initialize JWT functions
|
|
@@ -72,14 +98,13 @@ rbac_service = RBACService(
|
|
|
72
98
|
|
|
73
99
|
### 2. Authentication Setup
|
|
74
100
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
#### Option 1: Using the Package Middleware (Recommended)
|
|
78
|
-
|
|
79
|
-
The package middleware automatically handles JWT token validation and sets the user in the request state:
|
|
101
|
+
#### Option 1: Using Package Middleware (Recommended)
|
|
80
102
|
|
|
81
103
|
```python
|
|
82
104
|
from abs_auth_rbac_core.auth.middleware import auth_middleware
|
|
105
|
+
from fastapi import FastAPI, Depends
|
|
106
|
+
|
|
107
|
+
app = FastAPI()
|
|
83
108
|
|
|
84
109
|
# Create authentication middleware
|
|
85
110
|
auth_middleware = auth_middleware(
|
|
@@ -88,7 +113,7 @@ auth_middleware = auth_middleware(
|
|
|
88
113
|
jwt_algorithm=os.getenv("JWT_ALGORITHM", "HS256")
|
|
89
114
|
)
|
|
90
115
|
|
|
91
|
-
# Apply to specific routers
|
|
116
|
+
# Apply to specific routers
|
|
92
117
|
app.include_router(
|
|
93
118
|
protected_router,
|
|
94
119
|
dependencies=[Depends(auth_middleware)]
|
|
@@ -99,17 +124,16 @@ app.include_router(public_router)
|
|
|
99
124
|
```
|
|
100
125
|
|
|
101
126
|
**How it works:**
|
|
102
|
-
1.
|
|
103
|
-
2. Extracts
|
|
104
|
-
3. Fetches
|
|
105
|
-
4.
|
|
106
|
-
5. Returns
|
|
127
|
+
1. ✅ Validates JWT token from Authorization header
|
|
128
|
+
2. ✅ Extracts user UUID from token payload
|
|
129
|
+
3. ✅ Fetches user from database using UUID
|
|
130
|
+
4. ✅ Sets user object in `request.state.user`
|
|
131
|
+
5. ✅ Returns user object for route handlers
|
|
107
132
|
|
|
108
133
|
**Accessing the user in routes:**
|
|
109
134
|
```python
|
|
110
135
|
@router.get("/profile")
|
|
111
136
|
async def get_profile(request: Request):
|
|
112
|
-
# User is automatically available in request.state.user
|
|
113
137
|
user = request.state.user
|
|
114
138
|
return {"user_id": user.uuid, "email": user.email}
|
|
115
139
|
```
|
|
@@ -117,12 +141,11 @@ async def get_profile(request: Request):
|
|
|
117
141
|
#### Option 2: Custom Authentication Function
|
|
118
142
|
|
|
119
143
|
```python
|
|
120
|
-
from abs_auth_rbac_core.auth import JWTFunctions
|
|
144
|
+
from abs_auth_rbac_core.auth.jwt_functions import JWTFunctions
|
|
121
145
|
from fastapi import Security, HTTPAuthorizationCredentials
|
|
122
146
|
from fastapi.security import HTTPBearer
|
|
123
147
|
from abs_exception_core.exceptions import UnauthorizedError
|
|
124
148
|
|
|
125
|
-
# Create security scheme
|
|
126
149
|
security = HTTPBearer(auto_error=False)
|
|
127
150
|
jwt_functions = JWTFunctions(
|
|
128
151
|
secret_key=os.getenv("JWT_SECRET_KEY"),
|
|
@@ -138,7 +161,6 @@ async def get_current_user(
|
|
|
138
161
|
raise UnauthorizedError(detail="No authorization token provided")
|
|
139
162
|
|
|
140
163
|
token = credentials.credentials
|
|
141
|
-
# Remove 'Bearer ' prefix if present
|
|
142
164
|
if token.lower().startswith("bearer "):
|
|
143
165
|
token = token[7:]
|
|
144
166
|
|
|
@@ -150,7 +172,6 @@ async def get_current_user(
|
|
|
150
172
|
except Exception as e:
|
|
151
173
|
raise UnauthorizedError(detail=str(e))
|
|
152
174
|
|
|
153
|
-
# Use in individual routes
|
|
154
175
|
@app.get("/protected")
|
|
155
176
|
async def protected_route(current_user: dict = Depends(get_current_user)):
|
|
156
177
|
return {"message": f"Hello {current_user.get('name')}"}
|
|
@@ -180,35 +201,41 @@ has_permission = rbac_service.check_permission(
|
|
|
180
201
|
module="USER_MANAGEMENT"
|
|
181
202
|
)
|
|
182
203
|
|
|
183
|
-
# Get user permissions
|
|
204
|
+
# Get user permissions and roles
|
|
184
205
|
user_permissions = rbac_service.get_user_permissions(user_uuid="user_uuid")
|
|
185
206
|
user_roles = rbac_service.get_user_roles(user_uuid="user_uuid")
|
|
186
207
|
```
|
|
187
208
|
|
|
188
|
-
## Core Components
|
|
209
|
+
## 🏛️ Core Components
|
|
189
210
|
|
|
190
211
|
### Authentication (`auth/`)
|
|
191
|
-
-
|
|
192
|
-
-
|
|
193
|
-
-
|
|
212
|
+
- **`jwt_functions.py`**: JWT token management and password hashing
|
|
213
|
+
- **`middleware.py`**: Authentication middleware for FastAPI
|
|
214
|
+
- **`auth_functions.py`**: Core authentication functions
|
|
194
215
|
|
|
195
216
|
### RBAC (`rbac/`)
|
|
196
|
-
-
|
|
197
|
-
-
|
|
217
|
+
- **`service.py`**: Main RBAC service with role and permission management
|
|
218
|
+
- **`decorator.py`**: Decorators for permission checking
|
|
219
|
+
- **`policy.conf`**: Casbin policy configuration
|
|
198
220
|
|
|
199
221
|
### Models (`models/`)
|
|
200
|
-
-
|
|
201
|
-
-
|
|
202
|
-
-
|
|
203
|
-
-
|
|
204
|
-
-
|
|
205
|
-
-
|
|
206
|
-
-
|
|
222
|
+
- **`user.py`**: User model
|
|
223
|
+
- **`roles.py`**: Role model
|
|
224
|
+
- **`permissions.py`**: Permission model
|
|
225
|
+
- **`user_role.py`**: User-Role association model
|
|
226
|
+
- **`role_permission.py`**: Role-Permission association model
|
|
227
|
+
- **`user_permission.py`**: User-Permission association model
|
|
228
|
+
- **`rbac_model.py`**: Base RBAC model
|
|
229
|
+
- **`base_model.py`**: Base model with common fields
|
|
230
|
+
- **`gov_casbin_rule.py`**: Casbin rule model
|
|
231
|
+
|
|
232
|
+
### Schema (`schema/`)
|
|
233
|
+
- **`permission.py`**: Permission-related schemas
|
|
207
234
|
|
|
208
235
|
### Utilities (`util/`)
|
|
209
|
-
-
|
|
236
|
+
- **`permission_constants.py`**: Predefined permission constants and enums
|
|
210
237
|
|
|
211
|
-
## Complete Implementation Example
|
|
238
|
+
## 🔧 Complete Implementation Example
|
|
212
239
|
|
|
213
240
|
### 1. Dependency Injection Setup
|
|
214
241
|
|
|
@@ -216,6 +243,7 @@ user_roles = rbac_service.get_user_roles(user_uuid="user_uuid")
|
|
|
216
243
|
from dependency_injector import containers, providers
|
|
217
244
|
from abs_auth_rbac_core.auth.middleware import auth_middleware
|
|
218
245
|
from abs_auth_rbac_core.rbac import RBACService
|
|
246
|
+
from abs_auth_rbac_core.schema.permission import RedisWatcherSchema
|
|
219
247
|
from abs_auth_rbac_core.util.permission_constants import (
|
|
220
248
|
PermissionAction,
|
|
221
249
|
PermissionModule,
|
|
@@ -230,7 +258,6 @@ class Container(containers.DeclarativeContainer):
|
|
|
230
258
|
"src.api.endpoints.rbac.permission_route",
|
|
231
259
|
"src.api.endpoints.rbac.role_route",
|
|
232
260
|
"src.api.endpoints.rbac.users_route",
|
|
233
|
-
# Add other modules that need dependency injection
|
|
234
261
|
]
|
|
235
262
|
)
|
|
236
263
|
|
|
@@ -263,25 +290,24 @@ container = Container()
|
|
|
263
290
|
app.container = container
|
|
264
291
|
```
|
|
265
292
|
|
|
266
|
-
### 2.
|
|
293
|
+
### 2. Application Setup
|
|
267
294
|
|
|
268
295
|
```python
|
|
269
296
|
from fastapi import FastAPI, Depends
|
|
297
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
270
298
|
from dependency_injector.wiring import Provide, inject
|
|
271
299
|
from src.core.container import Container
|
|
272
300
|
|
|
273
|
-
@singleton
|
|
274
301
|
class CreateApp:
|
|
275
302
|
def __init__(self):
|
|
276
303
|
self.container = Container()
|
|
277
304
|
self.db = self.container.db()
|
|
278
|
-
# Get the auth middleware factory
|
|
279
305
|
self.auth_middleware = self.container.get_auth_middleware()
|
|
280
306
|
|
|
281
307
|
self.app = FastAPI(
|
|
282
308
|
title="Your Service",
|
|
283
309
|
description="Service Description",
|
|
284
|
-
version="0.0
|
|
310
|
+
version="0.2.0"
|
|
285
311
|
)
|
|
286
312
|
|
|
287
313
|
# Apply CORS middleware
|
|
@@ -326,11 +352,8 @@ from abs_auth_rbac_core.util.permission_constants import (
|
|
|
326
352
|
# Protected router (requires authentication)
|
|
327
353
|
router = APIRouter(prefix="/users")
|
|
328
354
|
|
|
329
|
-
# Public
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
# Public route example (no authentication or permissions required)
|
|
333
|
-
@public_router.post("/all", response_model=FindUserResult)
|
|
355
|
+
# Public route example
|
|
356
|
+
@router.post("/all", response_model=FindUserResult)
|
|
334
357
|
@inject
|
|
335
358
|
async def get_user_list(
|
|
336
359
|
request: Request,
|
|
@@ -359,197 +382,7 @@ async def get_user(
|
|
|
359
382
|
return service.get_user_profile("id", user_id, rbac_service)
|
|
360
383
|
```
|
|
361
384
|
|
|
362
|
-
|
|
363
|
-
1. The `@rbac_require_permission` decorator automatically extracts the user from `request.state.user`
|
|
364
|
-
2. Gets the user's UUID: `current_user_uuid = request.state.user.uuid`
|
|
365
|
-
3. Checks if the user has the required permissions using the RBAC service
|
|
366
|
-
4. If permission is denied, raises `PermissionDeniedError`
|
|
367
|
-
5. If permission is granted, the route handler executes normally
|
|
368
|
-
|
|
369
|
-
**Important:** The `request: Request` parameter is required in routes that use the `@rbac_require_permission` decorator because it needs access to `request.state.user`.
|
|
370
|
-
|
|
371
|
-
### Authentication Flow Overview
|
|
372
|
-
|
|
373
|
-
```
|
|
374
|
-
1. Client sends request with Authorization header
|
|
375
|
-
Authorization: Bearer <jwt_token>
|
|
376
|
-
|
|
377
|
-
2. Auth middleware intercepts the request
|
|
378
|
-
├── Validates JWT token
|
|
379
|
-
├── Extracts user UUID from token
|
|
380
|
-
├── Fetches user from database
|
|
381
|
-
└── Sets user in request.state.user
|
|
382
|
-
|
|
383
|
-
3. RBAC decorator checks permissions
|
|
384
|
-
├── Gets user UUID from request.state.user
|
|
385
|
-
├── Checks permissions against Casbin policies
|
|
386
|
-
└── Allows/denies access based on permissions
|
|
387
|
-
|
|
388
|
-
4. Route handler executes (if permissions granted)
|
|
389
|
-
└── Can access user via request.state.user
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
### Accessing Current User
|
|
393
|
-
|
|
394
|
-
#### In Routes with RBAC Decorator
|
|
395
|
-
```python
|
|
396
|
-
@router.get("/my-profile")
|
|
397
|
-
@inject
|
|
398
|
-
@rbac_require_permission(
|
|
399
|
-
f"{PermissionModule.USER_MANAGEMENT.value}:{PermissionResource.USER_MANAGEMENT.value}:{PermissionAction.VIEW.value}"
|
|
400
|
-
)
|
|
401
|
-
async def get_my_profile(
|
|
402
|
-
request: Request,
|
|
403
|
-
rbac_service: RBACService = Depends(Provide[Container.rbac_service]),
|
|
404
|
-
):
|
|
405
|
-
# Access current user from request state
|
|
406
|
-
current_user = request.state.user
|
|
407
|
-
return service.get_user_profile("uuid", current_user.uuid, rbac_service)
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
#### In Routes with Custom Auth Function
|
|
411
|
-
```python
|
|
412
|
-
@router.get("/profile")
|
|
413
|
-
async def get_profile(current_user: dict = Depends(get_current_user)):
|
|
414
|
-
# current_user is the decoded JWT payload
|
|
415
|
-
return {"user_id": current_user["uuid"], "email": current_user["email"]}
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
#### In Service Methods
|
|
419
|
-
```python
|
|
420
|
-
def some_service_method(self, user_uuid: str, rbac_service: RBACService):
|
|
421
|
-
# Get user permissions
|
|
422
|
-
permissions = rbac_service.get_user_permissions(user_uuid=user_uuid)
|
|
423
|
-
# Get user roles
|
|
424
|
-
roles = rbac_service.get_user_roles(user_uuid=user_uuid)
|
|
425
|
-
return {"permissions": permissions, "roles": roles}
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
@router.post("/create")
|
|
429
|
-
@inject
|
|
430
|
-
@rbac_require_permission(
|
|
431
|
-
f"{PermissionModule.USER_MANAGEMENT.value}:{PermissionResource.USER_MANAGEMENT.value}:{PermissionAction.CREATE.value}"
|
|
432
|
-
)
|
|
433
|
-
async def create_user(
|
|
434
|
-
user: CreateUserWithRoles,
|
|
435
|
-
request: Request,
|
|
436
|
-
rbac_service: RBACService = Depends(Provide[Container.rbac_service]),
|
|
437
|
-
):
|
|
438
|
-
"""Create a new user with roles"""
|
|
439
|
-
new_user = service.add_user(user)
|
|
440
|
-
|
|
441
|
-
# Assign roles if provided
|
|
442
|
-
if user.role_uuids and len(user.role_uuids) > 0 and new_user.uuid:
|
|
443
|
-
rbac_service.bulk_assign_roles_to_user(
|
|
444
|
-
user_uuid=new_user.uuid,
|
|
445
|
-
role_uuids=user.role_uuids,
|
|
446
|
-
)
|
|
447
|
-
return new_user
|
|
448
|
-
|
|
449
|
-
@router.patch("/{user_id}")
|
|
450
|
-
@inject
|
|
451
|
-
@rbac_require_permission(
|
|
452
|
-
f"{PermissionModule.USER_MANAGEMENT.value}:{PermissionResource.USER_MANAGEMENT.value}:{PermissionAction.EDIT.value}"
|
|
453
|
-
)
|
|
454
|
-
async def update_user(
|
|
455
|
-
user_id: int,
|
|
456
|
-
user: UpdateUserWithRoles,
|
|
457
|
-
request: Request,
|
|
458
|
-
rbac_service: RBACService = Depends(Provide[Container.rbac_service]),
|
|
459
|
-
):
|
|
460
|
-
"""Update user with new attributes and roles"""
|
|
461
|
-
return service.patch_user(user_id, user, rbac_service)
|
|
462
|
-
|
|
463
|
-
@router.delete("/{user_id}")
|
|
464
|
-
@inject
|
|
465
|
-
@rbac_require_permission(
|
|
466
|
-
f"{PermissionModule.USER_MANAGEMENT.value}:{PermissionResource.USER_MANAGEMENT.value}:{PermissionAction.DELETE.value}"
|
|
467
|
-
)
|
|
468
|
-
async def delete_user(
|
|
469
|
-
user_id: int,
|
|
470
|
-
request: Request,
|
|
471
|
-
rbac_service: RBACService = Depends(Provide[Container.rbac_service]),
|
|
472
|
-
):
|
|
473
|
-
"""Delete user"""
|
|
474
|
-
return service.remove_user(user_id, rbac_service)
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
### 3. Role and Permission Management
|
|
478
|
-
|
|
479
|
-
```python
|
|
480
|
-
@router.get("/roles")
|
|
481
|
-
@inject
|
|
482
|
-
@rbac_require_permission(
|
|
483
|
-
f"{PermissionModule.USER_MANAGEMENT.value}:{PermissionResource.ROLE_MANAGEMENT.value}:{PermissionAction.VIEW.value}"
|
|
484
|
-
)
|
|
485
|
-
async def get_roles(
|
|
486
|
-
request: Request,
|
|
487
|
-
rbac_service: RBACService = Depends(Provide[Container.rbac_service]),
|
|
488
|
-
):
|
|
489
|
-
"""Get all roles"""
|
|
490
|
-
return rbac_service.list_roles()
|
|
491
|
-
|
|
492
|
-
@router.post("/roles")
|
|
493
|
-
@inject
|
|
494
|
-
@rbac_require_permission(
|
|
495
|
-
f"{PermissionModule.USER_MANAGEMENT.value}:{PermissionResource.ROLE_MANAGEMENT.value}:{PermissionAction.CREATE.value}"
|
|
496
|
-
)
|
|
497
|
-
async def create_role(
|
|
498
|
-
role: CreateRoleSchema,
|
|
499
|
-
request: Request,
|
|
500
|
-
rbac_service: RBACService = Depends(Provide[Container.rbac_service]),
|
|
501
|
-
):
|
|
502
|
-
"""Create a new role with permissions"""
|
|
503
|
-
return rbac_service.create_role(
|
|
504
|
-
name=role.name,
|
|
505
|
-
description=role.description,
|
|
506
|
-
permission_ids=role.permission_ids
|
|
507
|
-
)
|
|
508
|
-
|
|
509
|
-
@router.get("/user-permissions/{user_uuid}")
|
|
510
|
-
@inject
|
|
511
|
-
@rbac_require_permission([
|
|
512
|
-
f"{PermissionModule.USER_MANAGEMENT.value}:{PermissionResource.USER_MANAGEMENT.value}:{PermissionAction.VIEW.value}",
|
|
513
|
-
f"{PermissionModule.USER_MANAGEMENT.value}:{PermissionResource.ROLE_MANAGEMENT.value}:{PermissionAction.VIEW.value}"
|
|
514
|
-
])
|
|
515
|
-
async def get_user_permissions(
|
|
516
|
-
user_uuid: str,
|
|
517
|
-
request: Request,
|
|
518
|
-
rbac_service: RBACService = Depends(Provide[Container.rbac_service]),
|
|
519
|
-
):
|
|
520
|
-
"""Get all permissions for a user"""
|
|
521
|
-
return rbac_service.get_user_permissions(user_uuid)
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
### 4. User Profile with Permissions
|
|
525
|
-
|
|
526
|
-
```python
|
|
527
|
-
def get_user_profile(self, attr: str, value: any, rbac_service: RBACService) -> UserProfile:
|
|
528
|
-
"""Get user profile with permissions and roles"""
|
|
529
|
-
user = self.user_repository.read_by_attr(attr, value, eager=True)
|
|
530
|
-
|
|
531
|
-
# Get user permissions and roles
|
|
532
|
-
permissions = rbac_service.get_user_permissions(user_uuid=user.uuid)
|
|
533
|
-
user_permissions = rbac_service.get_user_only_permissions(user_uuid=user.uuid)
|
|
534
|
-
roles = rbac_service.get_user_roles(user_uuid=user.uuid)
|
|
535
|
-
|
|
536
|
-
# Convert roles to response models
|
|
537
|
-
role_models = [UserRoleResponse.model_validate(role) for role in roles]
|
|
538
|
-
|
|
539
|
-
return UserProfile(
|
|
540
|
-
id=user.id,
|
|
541
|
-
uuid=user.uuid,
|
|
542
|
-
email=user.email,
|
|
543
|
-
name=user.name,
|
|
544
|
-
is_active=user.is_active,
|
|
545
|
-
last_login_at=user.last_login_at,
|
|
546
|
-
permissions=permissions,
|
|
547
|
-
user_permissions=user_permissions,
|
|
548
|
-
roles=role_models,
|
|
549
|
-
)
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
## Permission System
|
|
385
|
+
## 🔐 Permission System
|
|
553
386
|
|
|
554
387
|
### Permission Format
|
|
555
388
|
Permissions follow the format: `module:resource:action`
|
|
@@ -588,13 +421,13 @@ async def get_user_with_roles():
|
|
|
588
421
|
pass
|
|
589
422
|
```
|
|
590
423
|
|
|
591
|
-
## Configuration
|
|
424
|
+
## ⚙️ Configuration
|
|
592
425
|
|
|
593
426
|
### Environment Variables
|
|
594
427
|
|
|
595
428
|
```bash
|
|
596
429
|
# JWT Configuration
|
|
597
|
-
JWT_SECRET_KEY=your-secret-key
|
|
430
|
+
JWT_SECRET_KEY=your-secret-key-here
|
|
598
431
|
JWT_ALGORITHM=HS256
|
|
599
432
|
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=60
|
|
600
433
|
JWT_REFRESH_TOKEN_EXPIRE_MINUTES=1440
|
|
@@ -620,7 +453,104 @@ The package uses a default policy configuration that supports:
|
|
|
620
453
|
|
|
621
454
|
Policy format: `[role] [resource] [action] [module]`
|
|
622
455
|
|
|
623
|
-
##
|
|
456
|
+
## 🛠️ Advanced Usage
|
|
457
|
+
|
|
458
|
+
### User Profile with Permissions
|
|
459
|
+
|
|
460
|
+
```python
|
|
461
|
+
def get_user_profile(self, attr: str, value: any, rbac_service: RBACService) -> UserProfile:
|
|
462
|
+
"""Get user profile with permissions and roles"""
|
|
463
|
+
user = self.user_repository.read_by_attr(attr, value, eager=True)
|
|
464
|
+
|
|
465
|
+
# Get user permissions and roles
|
|
466
|
+
permissions = rbac_service.get_user_permissions(user_uuid=user.uuid)
|
|
467
|
+
user_permissions = rbac_service.get_user_only_permissions(user_uuid=user.uuid)
|
|
468
|
+
roles = rbac_service.get_user_roles(user_uuid=user.uuid)
|
|
469
|
+
|
|
470
|
+
# Convert roles to response models
|
|
471
|
+
role_models = [UserRoleResponse.model_validate(role) for role in roles]
|
|
472
|
+
|
|
473
|
+
return UserProfile(
|
|
474
|
+
id=user.id,
|
|
475
|
+
uuid=user.uuid,
|
|
476
|
+
email=user.email,
|
|
477
|
+
name=user.name,
|
|
478
|
+
is_active=user.is_active,
|
|
479
|
+
last_login_at=user.last_login_at,
|
|
480
|
+
permissions=permissions,
|
|
481
|
+
user_permissions=user_permissions,
|
|
482
|
+
roles=role_models,
|
|
483
|
+
)
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### Role and Permission Management
|
|
487
|
+
|
|
488
|
+
```python
|
|
489
|
+
@router.get("/roles")
|
|
490
|
+
@inject
|
|
491
|
+
@rbac_require_permission(
|
|
492
|
+
f"{PermissionModule.USER_MANAGEMENT.value}:{PermissionResource.ROLE_MANAGEMENT.value}:{PermissionAction.VIEW.value}"
|
|
493
|
+
)
|
|
494
|
+
async def get_roles(
|
|
495
|
+
request: Request,
|
|
496
|
+
rbac_service: RBACService = Depends(Provide[Container.rbac_service]),
|
|
497
|
+
):
|
|
498
|
+
"""Get all roles"""
|
|
499
|
+
return rbac_service.list_roles()
|
|
500
|
+
|
|
501
|
+
@router.post("/roles")
|
|
502
|
+
@inject
|
|
503
|
+
@rbac_require_permission(
|
|
504
|
+
f"{PermissionModule.USER_MANAGEMENT.value}:{PermissionResource.ROLE_MANAGEMENT.value}:{PermissionAction.CREATE.value}"
|
|
505
|
+
)
|
|
506
|
+
async def create_role(
|
|
507
|
+
role: CreateRoleSchema,
|
|
508
|
+
request: Request,
|
|
509
|
+
rbac_service: RBACService = Depends(Provide[Container.rbac_service]),
|
|
510
|
+
):
|
|
511
|
+
"""Create a new role with permissions"""
|
|
512
|
+
return rbac_service.create_role(
|
|
513
|
+
name=role.name,
|
|
514
|
+
description=role.description,
|
|
515
|
+
permission_ids=role.permission_ids
|
|
516
|
+
)
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
## 🔍 Authentication Flow
|
|
520
|
+
|
|
521
|
+
```
|
|
522
|
+
1. Client Request
|
|
523
|
+
┌─────────────────┐
|
|
524
|
+
│ Authorization: │
|
|
525
|
+
│ Bearer <token> │
|
|
526
|
+
└─────────────────┘
|
|
527
|
+
│
|
|
528
|
+
▼
|
|
529
|
+
2. Auth Middleware
|
|
530
|
+
┌──────────────────────┐
|
|
531
|
+
│ Validate JWT │
|
|
532
|
+
│ Extract User ID │
|
|
533
|
+
│ Fetch User │
|
|
534
|
+
│ Set in Request state │
|
|
535
|
+
└──────────────────────┘
|
|
536
|
+
│
|
|
537
|
+
▼
|
|
538
|
+
3. RBAC Decorator
|
|
539
|
+
┌─────────────────┐
|
|
540
|
+
│ Get User UUID │
|
|
541
|
+
│ Check Permissions│
|
|
542
|
+
│ Allow/Deny │
|
|
543
|
+
└─────────────────┘
|
|
544
|
+
│
|
|
545
|
+
▼
|
|
546
|
+
4. Route Handler
|
|
547
|
+
┌─────────────────┐
|
|
548
|
+
│ Execute Logic │
|
|
549
|
+
│ Return Response │
|
|
550
|
+
└─────────────────┘
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
## 🚨 Error Handling
|
|
624
554
|
|
|
625
555
|
The package includes comprehensive error handling:
|
|
626
556
|
|
|
@@ -647,40 +577,7 @@ except PermissionDeniedError as e:
|
|
|
647
577
|
return {"error": "Permission denied", "detail": str(e)}
|
|
648
578
|
```
|
|
649
579
|
|
|
650
|
-
##
|
|
651
|
-
|
|
652
|
-
### 1. Security
|
|
653
|
-
- Always use environment variables for sensitive data
|
|
654
|
-
- Implement proper password policies
|
|
655
|
-
- Regularly rotate JWT secret keys
|
|
656
|
-
- Use HTTPS in production
|
|
657
|
-
- Implement rate limiting for authentication endpoints
|
|
658
|
-
|
|
659
|
-
### 2. Permission Design
|
|
660
|
-
- Use descriptive permission names
|
|
661
|
-
- Group related permissions by module
|
|
662
|
-
- Implement least privilege principle
|
|
663
|
-
- Document permission requirements
|
|
664
|
-
|
|
665
|
-
### 3. Performance
|
|
666
|
-
- Use Redis for real-time policy updates
|
|
667
|
-
- Implement caching for frequently accessed permissions
|
|
668
|
-
- Optimize database queries with eager loading
|
|
669
|
-
- Monitor policy enforcement performance
|
|
670
|
-
|
|
671
|
-
### 4. Maintenance
|
|
672
|
-
- Regularly audit user permissions
|
|
673
|
-
- Implement permission cleanup for inactive users
|
|
674
|
-
- Monitor and log security events
|
|
675
|
-
- Keep dependencies updated
|
|
676
|
-
|
|
677
|
-
### 5. Testing
|
|
678
|
-
- Test all permission combinations
|
|
679
|
-
- Mock external dependencies
|
|
680
|
-
- Test error scenarios
|
|
681
|
-
- Implement integration tests
|
|
682
|
-
|
|
683
|
-
## Monitoring and Logging
|
|
580
|
+
## 📊 Monitoring and Logging
|
|
684
581
|
|
|
685
582
|
```python
|
|
686
583
|
import logging
|
|
@@ -698,29 +595,8 @@ logger.info(f"Permission check: {user_uuid} -> {resource}:{action}:{module}")
|
|
|
698
595
|
logger.info(f"Roles assigned to user {user_uuid}: {role_uuids}")
|
|
699
596
|
```
|
|
700
597
|
|
|
701
|
-
##
|
|
702
|
-
|
|
703
|
-
### Database Migrations
|
|
704
|
-
Ensure your database has the required tables:
|
|
705
|
-
- `users`
|
|
706
|
-
- `roles`
|
|
707
|
-
- `permissions`
|
|
708
|
-
- `user_roles`
|
|
709
|
-
- `role_permissions`
|
|
710
|
-
- `gov_casbin_rules`
|
|
598
|
+
## 🏥 Health Checks
|
|
711
599
|
|
|
712
|
-
### Redis Setup
|
|
713
|
-
For real-time policy updates, configure Redis:
|
|
714
|
-
```bash
|
|
715
|
-
# Install Redis
|
|
716
|
-
sudo apt-get install redis-server
|
|
717
|
-
|
|
718
|
-
# Configure Redis
|
|
719
|
-
redis-cli config set requirepass your-password
|
|
720
|
-
redis-cli config set notify-keyspace-events KEA
|
|
721
|
-
```
|
|
722
|
-
|
|
723
|
-
### Health Checks
|
|
724
600
|
```python
|
|
725
601
|
@app.get("/health")
|
|
726
602
|
async def health_check():
|
|
@@ -731,31 +607,117 @@ async def health_check():
|
|
|
731
607
|
}
|
|
732
608
|
```
|
|
733
609
|
|
|
734
|
-
## Troubleshooting
|
|
610
|
+
## 🔧 Troubleshooting
|
|
735
611
|
|
|
736
612
|
### Common Issues
|
|
737
613
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
614
|
+
| Issue | Solution |
|
|
615
|
+
|-------|----------|
|
|
616
|
+
| **Authentication Fails** | Check JWT secret key, token expiration, user existence |
|
|
617
|
+
| **Permission Denied** | Verify user roles, role-permission assignments, permission format |
|
|
618
|
+
| **Redis Connection Issues** | Check Redis server status, connection parameters, pub/sub support |
|
|
619
|
+
| **Policy Not Updating** | Verify Redis watcher configuration, policy format, Redis logs |
|
|
742
620
|
|
|
743
|
-
|
|
744
|
-
- Verify user has required roles
|
|
745
|
-
- Check role-permission assignments
|
|
746
|
-
- Validate permission format
|
|
621
|
+
### Debug Mode
|
|
747
622
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
623
|
+
```python
|
|
624
|
+
# Enable debug logging
|
|
625
|
+
import logging
|
|
626
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
752
627
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
628
|
+
# Check RBAC service status
|
|
629
|
+
print(f"Watcher active: {rbac_service.is_watcher_active()}")
|
|
630
|
+
print(f"Policy count: {rbac_service.get_policy_count()}")
|
|
631
|
+
```
|
|
757
632
|
|
|
758
|
-
##
|
|
633
|
+
## 📋 Dependencies
|
|
634
|
+
|
|
635
|
+
### Core Dependencies
|
|
636
|
+
- **pyjwt** (>=2.10.1,<3.0.0): JWT token handling
|
|
637
|
+
- **fastapi[standard]** (>=0.115.12,<0.116.0): Web framework
|
|
638
|
+
- **passlib** (>=1.7.4,<2.0.0): Password hashing
|
|
639
|
+
- **sqlalchemy** (>=2.0.40,<3.0.0): Database ORM
|
|
640
|
+
- **casbin** (>=1.41.0,<2.0.0): RBAC policy engine
|
|
641
|
+
- **casbin-sqlalchemy-adapter** (>=1.4.0,<2.0.0): Database adapter
|
|
642
|
+
- **casbin-redis-watcher** (>=1.3.0,<2.0.0): Real-time policy updates
|
|
643
|
+
|
|
644
|
+
### Internal Dependencies
|
|
645
|
+
- **abs-exception-core** (>=0.1.4,<0.2.0): Exception handling
|
|
646
|
+
- **psycopg2-binary** (>=2.9.10,<3.0.0): PostgreSQL adapter
|
|
647
|
+
|
|
648
|
+
## 🚀 Best Practices
|
|
649
|
+
|
|
650
|
+
### Security
|
|
651
|
+
- ✅ Use environment variables for sensitive data
|
|
652
|
+
- ✅ Implement proper password policies
|
|
653
|
+
- ✅ Regularly rotate JWT secret keys
|
|
654
|
+
- ✅ Use HTTPS in production
|
|
655
|
+
- ✅ Implement rate limiting for authentication endpoints
|
|
656
|
+
|
|
657
|
+
### Permission Design
|
|
658
|
+
- ✅ Use descriptive permission names
|
|
659
|
+
- ✅ Group related permissions by module
|
|
660
|
+
- ✅ Implement least privilege principle
|
|
661
|
+
- ✅ Document permission requirements
|
|
662
|
+
|
|
663
|
+
### Performance
|
|
664
|
+
- ✅ Use Redis for real-time policy updates
|
|
665
|
+
- ✅ Implement caching for frequently accessed permissions
|
|
666
|
+
- ✅ Optimize database queries with eager loading
|
|
667
|
+
- ✅ Monitor policy enforcement performance
|
|
668
|
+
|
|
669
|
+
### Maintenance
|
|
670
|
+
- ✅ Regularly audit user permissions
|
|
671
|
+
- ✅ Implement permission cleanup for inactive users
|
|
672
|
+
- ✅ Monitor and log security events
|
|
673
|
+
- ✅ Keep dependencies updated
|
|
674
|
+
|
|
675
|
+
## 📚 API Reference
|
|
676
|
+
|
|
677
|
+
### RBACService Methods
|
|
678
|
+
|
|
679
|
+
| Method | Description |
|
|
680
|
+
|--------|-------------|
|
|
681
|
+
| `create_role(name, description, permission_ids)` | Create a new role |
|
|
682
|
+
| `assign_role_to_user(user_uuid, role_uuid)` | Assign role to user |
|
|
683
|
+
| `bulk_assign_roles_to_user(user_uuid, role_uuids)` | Assign multiple roles |
|
|
684
|
+
| `check_permission(user_uuid, resource, action, module)` | Check user permission |
|
|
685
|
+
| `get_user_permissions(user_uuid)` | Get all user permissions |
|
|
686
|
+
| `get_user_roles(user_uuid)` | Get user roles |
|
|
687
|
+
| `list_roles()` | List all roles |
|
|
688
|
+
| `is_watcher_active()` | Check Redis watcher status |
|
|
689
|
+
|
|
690
|
+
### JWT Functions
|
|
691
|
+
|
|
692
|
+
| Method | Description |
|
|
693
|
+
|--------|-------------|
|
|
694
|
+
| `create_access_token(data)` | Create JWT access token |
|
|
695
|
+
| `decode_jwt(token)` | Decode and validate JWT |
|
|
696
|
+
| `hash_password(password)` | Hash password with bcrypt |
|
|
697
|
+
| `verify_password(password, hashed)` | Verify password hash |
|
|
698
|
+
|
|
699
|
+
## 📄 License
|
|
759
700
|
|
|
760
701
|
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
761
702
|
|
|
703
|
+
## 🤝 Contributing
|
|
704
|
+
|
|
705
|
+
1. Fork the repository
|
|
706
|
+
2. Create a feature branch
|
|
707
|
+
3. Make your changes
|
|
708
|
+
4. Add tests
|
|
709
|
+
5. Submit a pull request
|
|
710
|
+
|
|
711
|
+
## 📞 Support
|
|
712
|
+
|
|
713
|
+
For support and questions:
|
|
714
|
+
- Email: info@autobridgesystems.com
|
|
715
|
+
- Documentation: [Link to documentation]
|
|
716
|
+
- Issues: [GitHub Issues]
|
|
717
|
+
|
|
718
|
+
---
|
|
719
|
+
|
|
720
|
+
**Version**: 0.2.0
|
|
721
|
+
**Last Updated**: 2024
|
|
722
|
+
**Python Version**: >=3.12,<4.0
|
|
723
|
+
|