数据权限
约 439 字大约 1 分钟
数据权限是为了给数据添加权限而建立的,我们最常见的实现方式是仅本人数据,本部门数据... 这些就是所谓的数据权限,你可以控制不同的角色拥有不同的数据权限,从而实现用户和数据的隔离
弊端
如上所述,我们常见的这种数据权限,在大多数情况下,也能够满足日常场景所需,但是,这种常见的方式存在严重的弊端。由于数据权限的数据过滤是通过 SQL 语句拼接进行实现的,而这些固定权限,直接写死了数据权限的要求,例如:业务表必须包含 dept_id 和 created_by 字段, 如果没有这些业务字段,你就无法通过 SQL 来控制数据权限,下面是我对这种常规数据权限的实现,仅供参考:
def filter_data_permission(request: Request, model: Any) -> ColumnElement[bool]:
"""
过滤用户数据权限
:param request: 接口请求对象
:param model: 需要进行数据过滤的 sqlalchemy 模型
:return:
"""
user = request.user
# 超级管理员可查看所有数据
if user.is_superuser:
return or_(1 == 1)
user_id = user.id
user_roles = user.roles
# 无角色只能查看自己数据
if not user_roles:
return or_(getattr(model, 'created_by') == user_id if hasattr(model, 'created_by') else 1 == 0)
data_scope = min(role.data_scope for role in user_roles if role.status == 1)
user_dept_id = user.dept_id
# 全部数据权限
if data_scope == 0:
return or_(1 == 1)
# 自定义数据权限
elif data_scope == 1:
dept_ids = select(sys_role_dept.c.dept_id).where(
sys_role_dept.c.role_id.in_(role.id for role in user_roles if role.status == 1)
)
return or_(getattr(model, 'dept_id').in_(dept_ids) if hasattr(model, 'dept_id') else 1 == 0)
# 部门及以下数据权限
elif data_scope == 2:
child_dept_ids = select(Dept.id).where(or_(Dept.id == user_dept_id, Dept.parent_id == user_dept_id))
return or_(getattr(model, 'dept_id').in_(child_dept_ids) if hasattr(model, 'dept_id') else 1 == 0)
# 本部门数据权限
elif data_scope == 3:
return or_(getattr(model, 'dept_id') == user_dept_id if hasattr(model, 'dept_id') else 1 == 0)
# 仅本人数据权限
elif data_scope == 4:
return or_(getattr(model, 'created_by') == user_id if hasattr(model, 'created_by') else 1 == 0)
# 默认
else:
return or_(1 == 0)
请注意,当前 fba 中已删除此集成方式,你需要自行更新角色 model、schema,添加数据权限控制标识字段 data_scope 等相关代码
想法
有没有一种更加灵活的方案呢,答案是,当然有,目前,我们在 fba 中实现的正式超灵活方案,但是相对于常见方案来讲,可配更加复杂,但我们仍有很大的优化空间
你可以直接查看代码源文件 backend/common/security/permission.py
,其中,filter_data_permission 方法正是我们使用灵活方案,它与常规数据权限使用近乎相同的方式实现数据过滤,但由于其复杂性,下面,我们将通过视频进行讲解: 数据权限管理