Auth & RBAC
JWT Authentication
| Setting | Value |
|---|---|
| Algorithm | HS256 |
| Access Token | 12 hours |
| Refresh Token | 7 days |
| Password Hash | Argon2 |
Login Flow
POST /auth/login
→ Validate username + password (Argon2 verify)
→ Check account status (not disabled)
→ Generate access_token (12h) + refresh_token (7d)
→ Return tokens to frontendToken Refresh Flow
POST /auth/refresh-token
→ Validate refresh_token signature
→ Verify token type is "refresh"
→ Check user still exists and is active
→ Generate new access_token
→ Return new tokenToken Payload
json
{
"sub": "access", // "access" or "refresh"
"user_id": 1,
"exp": 1735689600
}RBAC Permission Control
Implemented as FastAPI dependencies in app/core/dependency.py.
AuthControl
Validates authentication on every protected request:
- Extract
Bearer <token>from Authorization header - Decode JWT and validate signature
- Check token type is "access"
- Query user from database
- Verify user is not disabled
- Store
user_idin context variable
python
@router.get("/users")
async def get_users(auth: AuthControl = Depends()):
# auth validates the JWT automatically
...PermissionControl
Validates RBAC permissions after authentication:
- Get current user's roles
- If role is
R_SUPER→ allow (skip all checks) - Get all APIs associated with user's roles
- Match current request
method + pathagainst role's APIs - If API is disabled → return
2200(API disabled) - If no match → return
2201(permission denied) - If matched and enabled → allow
python
@router.delete("/users/{user_id}")
async def delete_user(
user_id: int,
auth: AuthControl = Depends(),
perm: PermissionControl = Depends()
):
# Both auth and permission are checked
...Super Admin
The role with code R_SUPER has unrestricted access:
- Bypasses all API permission checks
- Has access to all routes
- Can manage all users, roles, and menus
Button-Level Permissions
Buttons are permission codes sent to the frontend in getUserInfo:
json
{
"buttons": ["B_USER_ADD", "B_USER_EDIT", "B_USER_DELETE"]
}The frontend conditionally renders buttons based on these codes.
Password Security
Passwords are hashed using Argon2 (recommended by OWASP):
python
from app.utils.security import hash_password, verify_password
hashed = hash_password("user_password")
is_valid = verify_password("user_password", hashed)