網站搜尋

typescript - 如何在 CASL 中使用 ForcedSubject


我正在按照 CASL 的手冊來實現具有預先定義權限的角色授權(見此處),但是當我嘗試檢查用戶的能力時遇到了阻礙。

我不明白 ForcedSubject 應該如何使用。我不想使用類別或介面來定義我的主題,因此我依賴字符串。然而,我所有的主題都包含一個 id 屬性,我希望能夠使用該 ID 的條件來檢查權限。以下是我實現的一個簡化版本。

import { Ability, AbilityClass, ForcedSubject } from '@casl/ability';

type OrgActions =
  | 'manage'
  | 'invite-user';

type SubjectWithId = { id: string };
type MyAbilities =
  | ['manage', 'all']
  | [OrgActions, 'organization' | ForcedSubject<SubjectWithId>];

export type MyAbility = Ability<MyAbilities>;
export const MyAbility = Ability as AbilityClass<MyAbility>;


const builder = new AbilityBuilder(PlatformAbility)
builder.can('invite-user', 'organization', { id: 'abcd' })

const ability = builder.build()
ability.can('invite-user', 'organization') // No problem here
ability.can('invite-user', subject('organization', { id: 'abcd' }) // Typing Error!

這是我收到的打字錯誤。

Argument of type '["invite-user", { id: string; } & ForcedSubject<"organization">]' is not assignable to parameter of type '[action: "manage", subject: "all", field?: string | undefined] | [action: OrgActions, subject: "organization" | ForcedSubject<SubjectWithId>, field?: string | undefined]'.
  Type '["invite-user", { id: string; } & ForcedSubject<"organization">]' is not assignable to type '[action: OrgActions, subject: "organization" | ForcedSubject<SubjectWithId>, field?: string | undefined]'.
    Type at position 1 in source is not compatible with type at position 1 in target.
      Type '{ id: string; } & ForcedSubject<"organization">' is not assignable to type '"organization" | ForcedSubject<SubjectWithId>'.
        Type '{ id: string; } & ForcedSubject<"organization">' is not assignable to type 'ForcedSubject<SubjectWithId>'.
          Types of property '__caslSubjectType__' are incompatible.
            Type 'string' is not assignable to type 'SubjectWithId'.ts(2345)

我不明白如果不使用像我那樣的 subject 助手,ForceSubject 類型應該如何使用。

答案#1

您遇到的錯誤是由於您傳遞給 ForcedSubject 的類型引起的。

你需要提供你的能力所期望的類型,而 subject 應該是強制你的對象轉換成的類型。在你的例子中,你希望 CASL 能識別被強制轉換成 'organization' 主體的普通對象,所以你需要將 'organization' 傳遞給 ForcedSubject。因此,你的類型 MyAbilities 應該如下所示:

type MyAbilities =
  | ['manage', 'all']
  | [OrgActions, 'organization' | ForcedSubject<'organization'>]

請注意,這允許你僅使某些主題類型可被強制使用,從而為可能使用類而非普通對象的任何主題類型提供更高的類型安全性。