优化权限控制

This commit is contained in:
yml2213
2026-06-22 17:07:29 +08:00
parent 480dfa6085
commit 8771d91a30
18 changed files with 222 additions and 16 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+7
View File
@@ -44,6 +44,13 @@ def _migrate():
conn.execute(text("ALTER TABLE accounts ADD COLUMN tag VARCHAR(64) DEFAULT ''"))
conn.commit()
# 检查 users.custom_permissions 列是否存在
result = conn.execute(text("PRAGMA table_info(users)"))
columns = [row[1] for row in result]
if 'custom_permissions' not in columns:
conn.execute(text("ALTER TABLE users ADD COLUMN custom_permissions JSON DEFAULT NULL"))
conn.commit()
def _seed():
"""写入默认超管账号和角色。"""
+2 -2
View File
@@ -8,7 +8,7 @@ from jose import JWTError
from .database import get_db
from .security import decode_access_token
from .models import User
from .permissions import get_role_permissions
from .permissions import get_user_permissions
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")
@@ -43,7 +43,7 @@ def require_permission(permission: str):
def checker(current_user: User = Depends(get_current_user)) -> User:
if not current_user.is_active:
raise HTTPException(status_code=403, detail="账号已禁用")
perms = get_role_permissions(current_user.role)
perms = get_user_permissions(current_user)
if permission not in perms:
raise HTTPException(status_code=403, detail=f"无权限: {permission}")
return current_user
+1
View File
@@ -18,6 +18,7 @@ class User(Base):
role = Column(String(32), nullable=False, default="support") # super_admin / operation / support
is_active = Column(Boolean, default=True)
remark = Column(String(256), default="")
custom_permissions = Column(JSON, nullable=True, comment="自定义权限列表,null表示使用角色默认权限")
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
+10 -1
View File
@@ -48,7 +48,6 @@ ROLE_PERMISSIONS = {
],
"support": [
"account:view_assigned",
"login:view_assigned",
],
}
@@ -65,6 +64,16 @@ def get_role_permissions(role: str) -> list[str]:
return ROLE_PERMISSIONS.get(role, [])
def get_user_permissions(user) -> list[str]:
"""获取用户的实际权限列表。
优先使用用户自定义权限(custom_permissions),
若为 None 则回退到角色默认权限。
"""
if user.custom_permissions is not None:
return user.custom_permissions
return get_role_permissions(user.role)
def has_permission(role: str, permission: str) -> bool:
"""检查角色是否拥有某权限。"""
return permission in get_role_permissions(role)
Binary file not shown.
+3 -3
View File
@@ -7,7 +7,7 @@ from sqlalchemy.orm import Session
from ..database import get_db
from ..models import User, AuditLog
from ..security import verify_password, create_access_token
from ..permissions import get_role_permissions, ROLE_LABELS
from ..permissions import get_user_permissions, ROLE_LABELS
from ..schemas import LoginRequest, TokenResponse
from ..deps import get_current_user
@@ -23,7 +23,7 @@ def login(req: LoginRequest, db: Session = Depends(get_db)):
raise HTTPException(status_code=403, detail="账号已禁用,请联系管理员")
token = create_access_token({"sub": str(user.id), "role": user.role})
perms = get_role_permissions(user.role)
perms = get_user_permissions(user)
# 审计
db.add(AuditLog(user_id=user.id, username=user.username, action="login", target="auth"))
@@ -46,7 +46,7 @@ def me(current_user: User = Depends(get_current_user)):
"role_label": ROLE_LABELS.get(current_user.role, current_user.role),
"is_active": current_user.is_active,
"remark": current_user.remark,
"permissions": get_role_permissions(current_user.role),
"permissions": get_user_permissions(current_user),
}
+19 -4
View File
@@ -6,7 +6,7 @@ from sqlalchemy.orm import Session
from ..database import get_db
from ..models import User, AuditLog
from ..security import hash_password
from ..permissions import ROLE_LABELS, get_role_permissions
from ..permissions import ROLE_LABELS, PERMISSIONS, get_user_permissions
from ..schemas import UserCreate, UserUpdate, UserInfo
from ..deps import require_permission, get_current_user
@@ -28,7 +28,8 @@ def list_users(
is_active=u.is_active,
remark=u.remark or "",
created_at=u.created_at,
permissions=get_role_permissions(u.role),
permissions=get_user_permissions(u),
custom_permissions=u.custom_permissions,
))
return result
@@ -60,7 +61,8 @@ def create_user(
return UserInfo(
id=user.id, username=user.username, role=user.role,
is_active=user.is_active, remark=user.remark or "",
permissions=get_role_permissions(user.role),
permissions=get_user_permissions(user),
custom_permissions=user.custom_permissions,
)
@@ -83,6 +85,8 @@ def update_user(
user.is_active = req.is_active
if req.remark is not None:
user.remark = req.remark
if req.custom_permissions is not None:
user.custom_permissions = req.custom_permissions
db.commit()
db.refresh(user)
@@ -94,7 +98,8 @@ def update_user(
return UserInfo(
id=user.id, username=user.username, role=user.role,
is_active=user.is_active, remark=user.remark or "",
permissions=get_role_permissions(user.role),
permissions=get_user_permissions(user),
custom_permissions=user.custom_permissions,
)
@@ -115,3 +120,13 @@ def delete_user(
db.delete(user)
db.commit()
return {"message": "已删除", "success": True}
@router.get("/permissions/list")
def list_permissions(_: User = Depends(require_permission("user:assign_permissions"))):
"""返回所有可用权限点及角色默认权限映射。"""
from ..permissions import ROLE_PERMISSIONS
return {
"permissions": PERMISSIONS,
"role_permissions": ROLE_PERMISSIONS,
}
+2
View File
@@ -27,6 +27,7 @@ class UserInfo(BaseModel):
remark: str = ""
created_at: Optional[datetime] = None
permissions: list[str] = []
custom_permissions: Optional[list[str]] = None
class Config:
from_attributes = True
@@ -45,6 +46,7 @@ class UserUpdate(BaseModel):
role: Optional[str] = None
is_active: Optional[bool] = None
remark: Optional[str] = None
custom_permissions: Optional[list[str]] = None
# ---- 账号 ----