在 JavaScript 的 `User` 模型中弃用 `user.groups`

这与 The road to stable, then permanent, for granular_anonymous_and_logged_in_groups_permissionsGranular group-based permissions for anonymous and logged in users 这两个主题都有关。

在核心代码以及许多主题和插件中,以下这种模式已经变得相当常见:

const groupIds = this.currentUser.groups.map((g) => g.id);
const allowedGroupIds = this.siteSettings.some_group_setting.split("|").map((groupId) => parseInt(groupId, 10));

const hasPermission = allowedGroups.some((groupId) =>
  userGroupIds.includes(groupId)
);

if (!hasPermission) {
  return;
}

然而,这并不是检查用户权限的有效方法。用户可以属于对他们不可见的组,因此这些组不会被序列化到客户端,也就无法在安全检查中一致或准确地使用。

为了使这一点更加明确,我们将在 User 模型中将 currentUser.groups/user.groups 重命名为 currentUser.visibleGroups/user.visibleGroups,并弃用旧属性。实现此变更的初始 PR 是 DEV: Deprecate calling user.groups on client directly - Pull Request #42711 - discourse/discourse - GitHub

如果你需要在客户端的 JavaScript 中基于组 ID 列表来检查用户权限,有几种替代方案:

针对插件

扩展 current_user 序列化器,添加一个新属性,并在服务器端使用 scope.in_any_groups? 来检查用户权限,该方法还涵盖了 logged_in_usersanonymous_users 等伪组:

add_to_serializer(
  :current_user,
  :has_some_permission,
  include_condition: -> do
    SiteSetting.plugin_enabled
  end,
) { scope.in_any_groups?(SiteSetting.group_list_setting_map) }

然后你可以在客户端使用 this.currentUser.has_some_permission

针对主题和组件

对于具有 list_type: grouplist 类型主题设置,你可以使用 resolve_group_membership: true

copy_button_allowed_groups:
  default: "1|3"
  type: list
  list_type: group
  resolve_group_membership: true

这将在客户端将 settings.copy_button_allowed_groups 替换为 settings.user_in_copy_button_allowed_groups(在设置前添加 user_in_ 前缀),这是一个基于用户组成员身份在服务器端计算的布尔值。

对于具有 type: groups 的对象设置,这也适用。在 groups 属性中添加 resolve_group_membership: true

menu_sections:
  type: objects
  default:
    - name: section 1
      groups:
        - 1
        - 3
  schema:
    name: menu section
    properties:
      name:
        type: string
      groups:
        type: groups
        resolve_group_membership: true

然后访问方式如下:

for (const section of settings.menu_sections) {
  if (section.user_in_groups) {
    // 用户属于该部分选定的至少一个组。
  }
}

嗨,Martin,
这些更改是在 PR 合并时生效,还是在 PR 合并后的下一次更新时生效?

这为什么重要?这不会导致任何功能损坏。它只会在浏览器控制台中显示一条警告,提醒开发人员调整其代码。

我有一些主题组件,我知道它们依赖于这个功能,所以想确认一下。如果这只是一个警告,而且功能还能维持一段时间,那我就没那么担心了。

通常,已弃用的代码会在下一个扩展支持版本发布之前继续获得支持。否则,使用这些代码的论坛将没有机会在问题出现之前看到警告。

该 PR 已经合并,因此现在已弃用:

不过,正如 Moin 所说,目前你只会收到浏览器控制台的弃用警告 :slight_smile: 当我们首次引入一项弃用功能时,必须先修复核心代码以及官方插件和主题中的所有相关实例。随后,我们会保留该弃用状态一段时间,以便逐步修复或让其他人修复第三方主题(包括客户定制的主题)。

在确保我们已捕获所有调用位置之前,user.groups 不会在相当长的一段时间内被永久移除。即便到了那时,我们也会先向仍在使用旧代码的站点显示管理员警告。