Pyramid“逐对象”权限:如何将应用GUID传入groupfinder()函数?
我之前也在多应用权限系统里踩过ACL的坑,完全理解你想按应用维度控制权限的需求!下面结合常见的多应用权限数据库架构,给你几个可行的实现思路:
思路1:通过请求上下文传递应用GUID
大多数Web框架都支持请求上下文(比如Flask的g对象、Django的request对象)。你可以在请求入口(比如中间件、全局装饰器)解析当前请求对应的应用GUID——比如从请求头X-App-GUID、URL路径参数、子域名里提取,然后把它存入请求上下文。在groupfinder()里直接从上下文获取这个GUID,再去数据库关联查询该用户在这个应用下所属的组。
举个伪代码例子:# 中间件里提取并存储应用GUID def app_identifier_middleware(request): app_guid = request.headers.get("X-App-GUID") # 存入框架上下文对象,以Flask为例 g.app_guid = app_guid return request # groupfinder实现 def groupfinder(user_id, request): app_guid = g.get("app_guid") if not app_guid: return [] # 无应用标识时返回空组,默认拒绝权限 # 数据库查询:关联用户、组、应用三者的关系 groups = db.query(Group.name)\ .join(UserGroup, Group.id == UserGroup.group_id)\ .join(AppGroup, Group.id == AppGroup.group_id)\ .filter(UserGroup.user_id == user_id, AppGroup.app_guid == app_guid)\ .all() return [g[0] for g in groups]思路2:将应用GUID作为groupfinder的参数绑定传入
如果你的权限系统(比如Pyramid的ACL体系)支持自定义groupfinder的参数,你可以通过闭包或者绑定参数的方式,把应用GUID直接传入groupfinder。这种方式适合单应用实例对应一个固定应用GUID的场景,比如工具箱里的每个应用都是独立部署的服务。
伪代码示例:def build_groupfinder(target_app_guid): # 闭包绑定目标应用GUID def groupfinder(user_id): groups = db.query(Group.name)\ .join(UserGroup, Group.id == UserGroup.group_id)\ .join(AppGroup, Group.id == AppGroup.group_id)\ .filter(UserGroup.user_id == user_id, AppGroup.app_guid == target_app_guid)\ .all() return [g[0] for g in groups] return groupfinder # 初始化权限策略时传入当前应用的GUID auth_policy = ACLAuthorizationPolicy(groupfinder=build_groupfinder("your-app-unique-guid"))思路3:在用户会话中存储当前应用GUID
如果用户需要先选择应用再进行操作,你可以在用户选择应用的环节,把应用GUID存入用户的会话(session)中。之后在groupfinder()里从会话中取出这个GUID进行权限查询,这种方式适合多应用共享同一个权限服务的场景:def groupfinder(user_id, request): app_guid = request.session.get("current_selected_app_guid") if not app_guid: return [] # 数据库查询逻辑同前 groups = db.query(Group.name)\ .join(UserGroup, Group.id == UserGroup.group_id)\ .join(AppGroup, Group.id == AppGroup.group_id)\ .filter(UserGroup.user_id == user_id, AppGroup.app_guid == app_guid)\ .all() return [g[0] for g in groups]额外优化建议
不管用哪种方式,都建议在数据库层面给app_guid、user_id、group_id这些关联字段建立联合索引,避免多表关联查询时性能下降;另外可以给groupfinder的查询结果加个短期缓存,减少重复查询数据库的次数。
内容的提问来源于stack exchange,提问作者Marcus Mann

