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;
}

그러나 이는 사용자 권한을 확인하는 효과적인 방법이 아닙니다. 사용자는 자신에게 표시되지 않는 그룹의 멤버가 될 수 있으며, 이러한 그룹은 클라이언트로 직렬화(serialization)되지 않아 보안 검사에 일관되고 정확하게 사용할 수 없습니다.

이 문제를 더 명확히 하기 위해 User 모델에서 currentUser.groups/user.groupscurrentUser.visibleGroups/user.visibleGroups로 이름 변경하고 기존 속성을 비추천(deprecated) 처리합니다. 이를 위한 초기 PR은 DEV: Deprecate calling user.groups on client directly - Pull Request #42711 - discourse/discourse - GitHub 입니다.

클라이언트에서 JavaScript를 사용하여 그룹 ID 목록에 기반한 사용자 권한을 확인해야 하는 경우 몇 가지 대안이 있습니다:

플러그인의 경우

current_user 직렬화기(serializer)에 새 속성을 추가하고, 서버 측에서 scope.in_any_groups?를 사용하여 사용자 권한을 확인하십시오. 이는 logged_in_usersanonymous_users와 같은 의사 그룹(pseudogroups)도 포함합니다:

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: group을 가진 list 타입의 테마 설정에서 resolve_group_membership: true를 사용할 수 있습니다:

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

이 경우 클라이언트에서 settings.copy_button_allowed_groupssettings.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) {
    // User is in at least one selected group for this section.
  }
}

마틴 씨, 안녕하세요.
이 변경 사항들은 PR이 병합되는 시점에 바로 적용되나요, 아니면 PR 병합 후 다음 업데이트 때 적용되나요?

이것이 왜 중요합니까? 아무것도 깨지지 않습니다. 단순히 브라우저 콘솔에 경고를 표시하여 개발자가 코드를 조정하도록 알릴 뿐입니다.

이 기능을 사용하는 테마 컴포넌트가 있다는 것을 알고 있어서 명확한 설명을 원합니다. 경고만 뜨고 당분간은 정상적으로 작동한다면 크게 걱정하지 않을 것 같습니다.

보통, 비권장(deprecated)된 코드는 다음 확장 지원 릴리스까지 계속 지원됩니다. 그렇지 않으면 해당 코드를 사용하는 포럼에서는 문제가 발생하기 전에 경고를 확인할 기회가 전혀 없게 됩니다.

PR이 이제 병합되었으므로 해당 기능은 비활성화(deprecated)되었습니다:

하지만 Moin이 말했듯이, 당분간은 브라우저 콘솔에 비활성화 경고만 표시됩니다 :slight_smile: 처음 비활성화를 도입할 때 코어와 공식 플러그인 및 테마에서 모든 인스턴스를 수정해야 하며, 그 후 비활성화 상태를 유지하면서 서드파티 테마(고객 테마 포함)를 점진적으로 수정하거나 다른 사람이 수정할 수 있도록 합니다.

user.groups의 영구적 제거는 모든 호출 위치를 확인한 후에야 이루어지며, 그전까지는 기존 사이트를 호출하는 코드가 남아 있는 사이트에 대해 먼저 관리자 경고를 표시합니다.