Architecture/Technical 在 Elixir Channels/Sockets 中处理 Authentication/Permissions 的挑战
Architecture/Technical Challenges in Handling Authentication/Permissions in Elixir Channels/Sockets
所以我决定将我在 Node.js 中编写的应用程序重写为 Elixir,因为 Elixir 开箱即用的 Node 具有额外的复杂性。
我的问题是我在 Node 中不太正确,在 Elixir 中变得同样复杂,我不完全确定如何着手解决它。
我正在尝试重现 Discord 如何处理权限。我本质上是在构建一个 CRM 系统,具有不同的角色,如 "Sales Manager"、"Sales"、"Customer Service Rep" 等......但他们都能够根据他们的 "role" 做不同的事情.
我需要做的一些事情是能够即时更新个人或角色的权限。也许 "Sales Manager" 角色不能像 "Accountant" 那样查看公司财务数据,但我们需要授予该特定人员几天的访问权限。或者我有一个 "Customer Service Rep",我们赋予整个角色向日历添加内容的能力。我也想有终止会话的能力。
所以我在 Elixir 论坛上看到了一些说法,比如:
- 使用 Guardian,我真的很想喜欢令牌,并且认为不必每次都访问数据库听起来很棒,但我认为这不实用。除非有一个我还没有找到的动态更新令牌的好方法。
- 给每个人自己的进程,然后在有新更改的情况下终止并启动该进程。这看起来很整洁,但我宁愿不终止进程,除非有实际错误,我认为这个解决方案会带来大问题,比如跟踪问题。虽然我不太熟悉这是否真的会导致问题,或者由于其他原因这是否是一个糟糕的解决方案。
- 将 Guardian 与 Guardian_DB 一起使用,这会破坏使用令牌的目的,但至少我会有一个可跟踪的会话。我唯一的问题是我确实计划使用负载平衡器,这样如果套接字连接中断,我可以将它重新连接到同一台服务器,但我不确定是否有办法用令牌来做到这一点,或者套接字本身是否有附加到它的会话。不过,这并不是什么大问题,而且非常接近我在 Node.js.
中遇到的问题
- 使用我想远离的Redis,然后在发生更新时根据user_id更新Redis中的会话数据,并在每个请求时点击Redis以查看用户是否有权限。我计划最终将它放在多个服务器上,这意味着 ETS 不可行,除非我可以像在 Node.js.
中那样对套接字连接进行负载平衡。
所以我想我的问题是,
- 我可以将会话附加到套接字吗?这是个坏主意吗?
- 我是否仍应使用令牌,并在每次请求时使用 Redis 检查令牌?
- 令牌仍然是比会话更好的选择吗?
- 有没有很多better/easier解决方案我都没有提到?
很抱歉,这太冗长了,我从来没有像这个项目那样专业地做过许可约束的事情,而且我对 Elixir 还很陌生。
Phoenix 通道是有状态的。您可以将数据放在 assigns
字段中,它会在连接期间保留在那里。这是您通常在对加入用户进行身份验证后放置 user_id 的位置。
我还使用分配的通道在服务器上存储我需要的客户端状态。
关于权限问题的角色,我正在这样做。我所做的是在启动时从数据库加载角色权限,并用它们构建一个 ETS 存储。您可以对任务或 GenServer 执行相同的操作。如果给定角色的权限发生变化,我会更新数据库和 ETS table。
我的用户模型支持每个用户的角色列表。
当需要验证给定用户的权限时,我将权限模型 api 称为 Permission.has_permission?("create-room", user, scope)
。我有两级权限,全局权限和每个房间权限。这就是范围的用途。
所以我决定将我在 Node.js 中编写的应用程序重写为 Elixir,因为 Elixir 开箱即用的 Node 具有额外的复杂性。
我的问题是我在 Node 中不太正确,在 Elixir 中变得同样复杂,我不完全确定如何着手解决它。
我正在尝试重现 Discord 如何处理权限。我本质上是在构建一个 CRM 系统,具有不同的角色,如 "Sales Manager"、"Sales"、"Customer Service Rep" 等......但他们都能够根据他们的 "role" 做不同的事情.
我需要做的一些事情是能够即时更新个人或角色的权限。也许 "Sales Manager" 角色不能像 "Accountant" 那样查看公司财务数据,但我们需要授予该特定人员几天的访问权限。或者我有一个 "Customer Service Rep",我们赋予整个角色向日历添加内容的能力。我也想有终止会话的能力。
所以我在 Elixir 论坛上看到了一些说法,比如:
- 使用 Guardian,我真的很想喜欢令牌,并且认为不必每次都访问数据库听起来很棒,但我认为这不实用。除非有一个我还没有找到的动态更新令牌的好方法。
- 给每个人自己的进程,然后在有新更改的情况下终止并启动该进程。这看起来很整洁,但我宁愿不终止进程,除非有实际错误,我认为这个解决方案会带来大问题,比如跟踪问题。虽然我不太熟悉这是否真的会导致问题,或者由于其他原因这是否是一个糟糕的解决方案。
- 将 Guardian 与 Guardian_DB 一起使用,这会破坏使用令牌的目的,但至少我会有一个可跟踪的会话。我唯一的问题是我确实计划使用负载平衡器,这样如果套接字连接中断,我可以将它重新连接到同一台服务器,但我不确定是否有办法用令牌来做到这一点,或者套接字本身是否有附加到它的会话。不过,这并不是什么大问题,而且非常接近我在 Node.js. 中遇到的问题
- 使用我想远离的Redis,然后在发生更新时根据user_id更新Redis中的会话数据,并在每个请求时点击Redis以查看用户是否有权限。我计划最终将它放在多个服务器上,这意味着 ETS 不可行,除非我可以像在 Node.js. 中那样对套接字连接进行负载平衡。
所以我想我的问题是,
- 我可以将会话附加到套接字吗?这是个坏主意吗?
- 我是否仍应使用令牌,并在每次请求时使用 Redis 检查令牌?
- 令牌仍然是比会话更好的选择吗?
- 有没有很多better/easier解决方案我都没有提到?
很抱歉,这太冗长了,我从来没有像这个项目那样专业地做过许可约束的事情,而且我对 Elixir 还很陌生。
Phoenix 通道是有状态的。您可以将数据放在 assigns
字段中,它会在连接期间保留在那里。这是您通常在对加入用户进行身份验证后放置 user_id 的位置。
我还使用分配的通道在服务器上存储我需要的客户端状态。
关于权限问题的角色,我正在这样做。我所做的是在启动时从数据库加载角色权限,并用它们构建一个 ETS 存储。您可以对任务或 GenServer 执行相同的操作。如果给定角色的权限发生变化,我会更新数据库和 ETS table。
我的用户模型支持每个用户的角色列表。
当需要验证给定用户的权限时,我将权限模型 api 称为 Permission.has_permission?("create-room", user, scope)
。我有两级权限,全局权限和每个房间权限。这就是范围的用途。