abs-auth-rbac-core 0.2.1__py3-none-any.whl → 0.2.2__py3-none-any.whl

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.

@@ -155,7 +155,10 @@ class RBACService:
155
155
  """
156
156
  with self.db() as session:
157
157
  try:
158
- if hasattr(permissions,'model_dump'):
158
+ if not permissions:
159
+ return []
160
+
161
+ if hasattr(permissions[0],'model_dump'):
159
162
  add_permissions = [Permission(**permission.model_dump()) for permission in permissions]
160
163
  else:
161
164
  add_permissions = [Permission(**permission) for permission in permissions]
@@ -205,66 +208,77 @@ class RBACService:
205
208
  Assign permissions to a user
206
209
  """
207
210
  with self.db() as session:
208
- current_permissions = session.query(UserPermission).filter(UserPermission.user_uuid==user_uuid).all()
209
- current_permission_uuids = [permission.permission_uuid for permission in current_permissions]
210
- remove_permissions = set(current_permission_uuids) - set(permission_uuids)
211
- add_permissions = set(permission_uuids) - set(current_permission_uuids)
212
- if remove_permissions:
213
- self.revoke_user_permissions(user_uuid,list(remove_permissions))
214
- if add_permissions:
215
- self.attach_permissions_to_user(user_uuid,list(add_permissions))
216
- return self.get_user_only_permissions(user_uuid)
211
+ try:
212
+ current_permissions = session.query(UserPermission).filter(UserPermission.user_uuid==user_uuid).all()
213
+ current_permission_uuids = [permission.permission_uuid for permission in current_permissions]
214
+ remove_permissions = set(current_permission_uuids) - set(permission_uuids)
215
+ add_permissions = set(permission_uuids) - set(current_permission_uuids)
216
+ if remove_permissions:
217
+ self.revoke_user_permissions(user_uuid,list(remove_permissions))
218
+ if add_permissions:
219
+ self.attach_permissions_to_user(user_uuid,list(add_permissions))
220
+ return self.get_user_only_permissions(user_uuid)
221
+ except Exception as e:
222
+ raise e
217
223
 
218
224
  def attach_permissions_to_user(self, user_uuid: str, permission_uuids: List[str]):
219
225
  with self.db() as session:
220
- user_permissions = [
221
- UserPermission(user_uuid=user_uuid, permission_uuid=permission_uuid)
222
- for permission_uuid in permission_uuids
223
- ]
224
- session.bulk_save_objects(user_permissions)
225
- session.commit()
226
-
227
- permissions = session.query(Permission).filter(Permission.uuid.in_(permission_uuids)).all()
228
- policies = [
229
- [f"user:{user_uuid}", permission.resource, permission.action, permission.module]
230
- for permission in permissions
231
- ]
232
- added_policies = self.enforcer.add_policies(policies)
233
- if added_policies:
234
- self.enforcer.save_policy()
235
- self.enforcer.load_policy()
236
- return self.get_user_only_permissions(user_uuid)
226
+ try:
227
+ user_permissions = [
228
+ UserPermission(user_uuid=user_uuid, permission_uuid=permission_uuid)
229
+ for permission_uuid in permission_uuids
230
+ ]
231
+ session.bulk_save_objects(user_permissions)
232
+ session.commit()
237
233
 
234
+ permissions = session.query(Permission).filter(Permission.uuid.in_(permission_uuids)).all()
235
+ policies = [
236
+ [f"user:{user_uuid}", permission.resource, permission.action, permission.module]
237
+ for permission in permissions
238
+ ]
239
+ added_policies = self.enforcer.add_policies(policies)
240
+ if added_policies:
241
+ self.enforcer.save_policy()
242
+ self.enforcer.load_policy()
243
+ return self.get_user_only_permissions(user_uuid)
244
+ except Exception as e:
245
+ raise e
238
246
 
239
247
  def revoke_user_permissions(self, user_uuid: str, permission_uuids: List[str]):
240
248
  with self.db() as session:
241
- user_permissions = session.query(UserPermission).filter(
242
- UserPermission.user_uuid == user_uuid,
243
- UserPermission.permission_uuid.in_(permission_uuids)
244
- )
249
+ try:
250
+ user_permissions = session.query(UserPermission).filter(
251
+ UserPermission.user_uuid == user_uuid,
252
+ UserPermission.permission_uuid.in_(permission_uuids)
253
+ )
245
254
 
246
- permissions = session.query(Permission).filter(Permission.uuid.in_(permission_uuids)).all()
247
- policies = [
248
- [f"user:{user_uuid}", permission.resource, permission.action, permission.module]
249
- for permission in permissions
250
- ]
251
- removed_policies = self.enforcer.remove_policies(policies)
252
- if removed_policies:
253
- self.enforcer.save_policy()
254
- self.enforcer.load_policy()
255
- user_permissions.delete(synchronize_session=False)
256
- session.commit()
257
- return self.get_user_only_permissions(user_uuid)
255
+ permissions = session.query(Permission).filter(Permission.uuid.in_(permission_uuids)).all()
256
+ policies = [
257
+ [f"user:{user_uuid}", permission.resource, permission.action, permission.module]
258
+ for permission in permissions
259
+ ]
260
+ removed_policies = self.enforcer.remove_policies(policies)
261
+ if removed_policies:
262
+ self.enforcer.save_policy()
263
+ self.enforcer.load_policy()
264
+ user_permissions.delete(synchronize_session=False)
265
+ session.commit()
266
+ return self.get_user_only_permissions(user_uuid)
267
+ except Exception as e:
268
+ raise e
258
269
 
259
270
  def list_roles(self) -> Any:
260
271
  """
261
272
  Get the list of all roles
262
273
  """
263
274
  with self.db() as session:
264
- """List all roles"""
265
- total = session.query(Role).count()
266
- roles = session.query(Role).all()
267
- return {"roles": roles, "total": total}
275
+ try:
276
+ """List all roles"""
277
+ total = session.query(Role).count()
278
+ roles = session.query(Role).all()
279
+ return {"roles": roles, "total": total}
280
+ except Exception as e:
281
+ raise e
268
282
 
269
283
  def create_role(
270
284
  self,
@@ -940,7 +954,7 @@ class RBACService:
940
954
  self.enforcer.load_policy()
941
955
  return True
942
956
  except Exception as e:
943
- print(f"Failed to reload policies: {e}")
957
+ logger.error(f"Failed to reload policies: {e}")
944
958
  return False
945
959
 
946
960
  def get_policy_count(self) -> int:
@@ -954,5 +968,5 @@ class RBACService:
954
968
  self.enforcer.save_policy()
955
969
  return True
956
970
  except Exception as e:
957
- print(f"Failed to clear policies: {e}")
971
+ logger.error(f"Failed to clear policies: {e}")
958
972
  return False
@@ -1,15 +1,16 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: abs-auth-rbac-core
3
- Version: 0.2.1
3
+ Version: 0.2.2
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.13,<4.0
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.0,<0.2.0)
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
- - **JWT-based Authentication**: Secure token-based authentication with customizable expiration
30
- - **Password Hashing**: Secure password storage using bcrypt
31
- - **Role-Based Access Control (RBAC)**: Flexible permission management using Casbin
32
- - **Real-time Policy Updates**: Redis integration for live policy synchronization
33
- - **User-Role Management**: Dynamic role assignment and revocation
34
- - **Permission Enforcement**: Decorator-based permission checking
35
- - **Middleware Integration**: Seamless FastAPI middleware integration
36
- - **Comprehensive Error Handling**: Built-in exception handling for security scenarios
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
- ## Quick Start
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
- The auth middleware can be implemented in two ways:
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 (recommended approach)
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. The middleware validates the JWT token from the Authorization header
103
- 2. Extracts the user UUID from the token payload
104
- 3. Fetches the user from the database using the UUID
105
- 4. **Sets the user object in `request.state.user`**
106
- 5. Returns the user object for use in route handlers
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
- - `jwt_functions.py`: JWT token management and password hashing
192
- - `middleware.py`: Authentication middleware for FastAPI
193
- - `auth_functions.py`: Core authentication functions
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
- - `service.py`: Main RBAC service with role and permission management
197
- - `decorator.py`: Decorators for permission checking
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
- - `user.py`: User model
201
- - `roles.py`: Role model
202
- - `permissions.py`: Permission model
203
- - `user_role.py`: User-Role association model
204
- - `role_permission.py`: Role-Permission association model
205
- - `rbac_model.py`: Base RBAC model
206
- - `base_model.py`: Base model with common fields
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
- - `permission_constants.py`: Predefined permission constants and enums
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. Complete Application Setup
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.1"
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 router (no authentication required)
330
- public_router = APIRouter(prefix="/users")
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
- **How the RBAC decorator works:**
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
- ## Error Handling
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
- ## Best Practices
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
- ## Migration and Deployment
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
- 1. **Authentication Fails**
739
- - Check JWT secret key configuration
740
- - Verify token expiration settings
741
- - Ensure user exists in database
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
- 2. **Permission Denied**
744
- - Verify user has required roles
745
- - Check role-permission assignments
746
- - Validate permission format
621
+ ### Debug Mode
747
622
 
748
- 3. **Redis Connection Issues**
749
- - Check Redis server status
750
- - Verify connection parameters
751
- - Ensure Redis supports pub/sub
623
+ ```python
624
+ # Enable debug logging
625
+ import logging
626
+ logging.basicConfig(level=logging.DEBUG)
752
627
 
753
- 4. **Policy Not Updating**
754
- - Check Redis watcher configuration
755
- - Verify policy format
756
- - Monitor Redis logs
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
- ## License
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
+
@@ -17,11 +17,11 @@ abs_auth_rbac_core/models/user_role.py,sha256=20pqmtJPzlUrI9ulHGouk8XlFgrGG7I6ik
17
17
  abs_auth_rbac_core/rbac/__init__.py,sha256=oYjtpmfrkEbwWCBAWuRoU1fM4fCpBxkF_lwQrelK1As,79
18
18
  abs_auth_rbac_core/rbac/decorator.py,sha256=pEFAW0Nn2iE4KBctPhNOmO_VLeJFDX2V9v2LsCu6kHY,1824
19
19
  abs_auth_rbac_core/rbac/policy.conf,sha256=wghhhKxgZH0rPhh1QFrIpq9nevJT3s7OxxvXiU3zzuI,305
20
- abs_auth_rbac_core/rbac/service.py,sha256=YKur4trtTc0N-u3oqrfAJf9yLOTzSU-Pn2qh5drciqs,37250
20
+ abs_auth_rbac_core/rbac/service.py,sha256=zzHvbROqUpgKSLghJ7bDnxDHWkF1tyMG9XObxu0KwoY,37837
21
21
  abs_auth_rbac_core/schema/__init__.py,sha256=v9xibJ8Wr9k0u6PEYNK0LCGUJD71SB5vxu9BZG0S7tM,46
22
22
  abs_auth_rbac_core/schema/permission.py,sha256=XvxPU68FY0PFgkF4GR2bSrzNvFB8c8OgY_d0JOJvMc8,203
23
23
  abs_auth_rbac_core/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  abs_auth_rbac_core/util/permission_constants.py,sha256=cUEi6S9iNK4jwxevlb4ZNiBUcFSu4wlkN-p-O3-l7xs,95712
25
- abs_auth_rbac_core-0.2.1.dist-info/METADATA,sha256=QJwW0gy1QBOjN4oR2dT7EPEZLKBGvWMVQjo3JbVZ-sQ,23269
26
- abs_auth_rbac_core-0.2.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
27
- abs_auth_rbac_core-0.2.1.dist-info/RECORD,,
25
+ abs_auth_rbac_core-0.2.2.dist-info/METADATA,sha256=AzbbtCtxZs_h8TPFcVhWZQ9n7yoCiLRpDPR4cQ4J9DQ,23498
26
+ abs_auth_rbac_core-0.2.2.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
27
+ abs_auth_rbac_core-0.2.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: poetry-core 2.1.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any