0

我正在构建我的多租户 Symfony 应用程序的下一个版本。

可以说我的租户是公司。每个公司都有我的应用程序域的子域。

例如,company1.example.com、company2.example.com。

Apache 配置了 ServerAlias *.example.com

我编写了一个 UserProvider,以便用户在公司和电子邮件地址中是唯一的。相同的电子邮件地址可以在 company1 和 company2 注册,但就 Symfony 而言,它们是不同的用户。我有一项服务,它查看主机名以确定公司。FilterControllerEvent 处理程序使 Company 对象神奇地在控制器中可用。

这一切都很好。

但是……那些公司有部门。例如,公司 1 - 部门 1,

公司 1 - 部门 2,

公司 2 - 部门 3

对于大多数操作,divideId 将是第一个参数,所以 ...

company1.example.com/1

company1.example.com/2

现在的并发症。一个用户可能在不同的部门有不同的角色。company1 的用户 1 可能在部门 1 有 ROLE_BOSS,但在部门 2 有 ROLE_WORKER。

UserProvider 从数据库加载角色。这目前基于电子邮件地址和公司,但是......它也可以基于 URL 参数吗?我想我需要将 Request 对象注入我的 UserProvider 并查看属性。这种方法有什么问题吗?这有点太笨拙了吗?

我一直在燃烧大脑周期,试图找出最好的方法来做到这一点。我的要求基本上是:

  • 公司用户的单一登录(基于电子邮件地址),即使他们访问多个部门并且在这些部门中具有不同的角色。

  • 公司不相关,因此允许不同公司使用相同的电子邮件地址。如果用户确实在多家公司拥有帐户,那么他可以分别登录每个公司并使用书签或其他方式在它们之间进行访问。对于用户来说,它们是独立的、不相关的站点。

  • 用户应该能够在部门之间进行切换,而无需再次登录。

  • Symfony 防火墙系统应该“正常工作”。User1 应该能够访问 company1.example.com/1/BossStuff 但不能访问 company1.example.com/2/BossStuff 仅基于我的 UserProvider 加载的角色,而不是每个控制器操作中繁琐的安全检查代码(在那里做过) .

我考虑过的其他方法是...

  • 每个部门都有一个唯一的子域。部门 id 表示公司 id,因此用户仍然可以是公司唯一的。我们不再需要 divisionId URL 参数。那么问题是用户在同一公司的部门之间移动时需要登录。

  • 上述部门的唯一子域,但将 PHP 会话 cookie 设为 .example.com 而不是子域。这解决了在部门之间再次登录的需要,但如果你想在公司之间切换会变得混乱。您无法同时登录 company1 和 company2。

  • 同样,部门的唯一子域,子域中的 cookie,但有一些其他身份验证机制,因此当登录到 company1-division1.example.com 时,它会在 .example.com 上放置一个唯一的 cookie,因此如果您随后访问 company1-division2.example .com,它会读取该 cookie 并自动将您登录。可能有效,但从安全角度来看会有点混乱和可怕。我不确定我是否想去那里。

我已经阅读了有关身份验证提供程序、访问控制列表、选民等的信息。我认为它们在这里对我没有多大帮助。

感谢您的任何想法。

4

1 回答 1

0

回答我自己的问题。这似乎工作正常。

总而言之,也许以更简单的方式......我在 http://www.example.com 有一个站点,在http://www.example.com/1和 http://www.example.com几个子站点/2http://www.example.com/3等。我希望登录用户在不同的子站点具有不同的角色。我的用户提供商查看 Request::attributes->get('_route_params') 以从 URL 获取子站点 id 参数。我的 UserProvider::loadUserByUsername 和 UserProvider::refreshUser 返回具有适合该子站点的角色的用户。

一个问题是 AbstractToken 序列化当前角色并将它们保存在会话中以便在下一个请求时恢复。这意味着在 UserProvider::refreshUser 中简单地返回不同的角色不会刷新角色。这个问题是这个线程的主题:https ://groups.google.com/forum/#!topic/symfony2/NDBb4JN3mNc 。这可以通过确保 User::isEqualTo 在角色已更改时返回 false 来解决。就我而言,如果 subsiteId 已更改,我将返回 false。这迫使 Symfony 重新进行身份验证,因此在下次检查角色时重新加载角色。那是在显式调用 SecurityContext::isGranted 或命中防火墙规则时。

一开始让人有点不安的感觉是,如果您切换子站点而不检查角色(例如,转到公共页面),那么 Symfony 分析器会说“Authenticated: No”。当角色被选中时,这将变为是。我认为没关系。一切都在重要的时候正确发生,即,当我需要按角色控制访问时。

于 2013-11-07T19:18:52.440 回答