Symfony 中的单数据库多租户:一个 31 行的 Doc... 笔记

Symfony 中的单数据库多租户:一个 31 行的 Doctrine 过滤器,以及它永不执行的五个场景

单数据库多租户架构依赖 organization_id 列来强制数据隔离,但开发人员必须在查询中包含该列。Doctrine 的 SQLFilter 可自动化此过程,但其有效性取决于其实现位置及被省略的位置。组织过滤器在 Doctrine 配置中默认被禁用,以防止对 fixtures、迁移脚本和修复脚本造成问题。它通过请求生命周期后期的监听器启用,具体是在防火墙之后,以便访问已认证用户及其所属组织。然而,该过滤器存在若干盲区,在这些场景中它不适用或被绕过。控制台命令和消息队列工作进程无法受益于请求监听器,因此执行时过滤器未启用。虽然这对于跨所有租户的批量处理等任务而言是有意为之,但涉及租户数据的命令需要显式指定作用域。管理面板也通过路径前缀被有意豁免,以便跨租户查看数据,此类豁免具有关键的安全性影响。在查询执行前已存在于 Doctrine 身份映射中的实体将完全绕过过滤器,因为不会生成 SQL。同样,getReference() 会创建无需数据库交互的代理对象,意味着过滤器直到代理被初始化时才会被咨询。通过 DBAL 执行的原始 SQL 查询会完全忽略 Doctrine 的过滤器,这对报表和导出功能构成风险。即使存在民间说法,联合继承若未在根实体上包含 organization_id 和标记接口,也可能导致过滤遗漏。尽管有传言称过滤器适用于批量 UPDATE 和 DELETE DQL 语句,但这仅涵盖 DQL 路径。彻底的自动化测试对于确保过滤器的可靠性并捕获回归问题至关重要。