我如何访问 CASL 条件的嵌套属性
how can i access nested properties for CASL conditions
我似乎无法使用条件规则访问嵌套对象。
如果文章的评论与用户具有相同的 ID,我希望用户有权删除文章。
这些只是一些编造的 类 来测试...
这是我的代码:
import { defineAbility, AbilityBuilder } from '@casl/ability';
import { Ability, AbilityClass, ExtractSubjectType, InferSubjects } from '@casl/ability';
export class Article {
static readonly modelName = "Article";
static readonly __typename = "Article";
constructor( id: number,
title: string,
content: string,
user: User,
comment: Comment) {
this.id = id
this.title = title
this.content = content
this.user = user
this.comment = comment
}
id: number
title: string
content: string
user: User
comment: Comment
}
export class User {
static readonly modelName = "User"
static readonly __typename = "User";
constructor (id: number,
name: string,
comment: Comment) {
this.id = id
this.name = name
this.comment = comment
}
id: number
name: string
comment: Comment
}
export class Comment {
static readonly modelName = "Comment"
static readonly __typename = "Comment";
constructor(id: number,
content: string,
authorId: number) {
this.id = id
this.content = content
this.authorId = authorId
}
id: number
content: string
authorId: number
}
type Action = 'create' | 'read' | 'update' | 'delete';
type Subjects = InferSubjects<typeof Article | typeof Comment| typeof User, true>;
export type AppAbility = Ability<[Action, Subjects]>;
export function createForUser(user: User) {
const { can, cannot, build } = new AbilityBuilder<
Ability<[Action, Subjects]>
>(Ability as AbilityClass<AppAbility>);
can('delete', Article, { comment: {id: user.comment.id}})
return build({
detectSubjectType: item => item.constructor as ExtractSubjectType<Subjects>
});
}
我用以下方法测试它:
const comment = new Comment(0, 'a', 0)
const user = new User(1, 'sd', comment);
const article = new Article(2, 'sd', 'asd', user, comment)
const ability = createForUser(user);
console.log(ability.can('delete', article))// false
我在某个地方看到我需要做这样的事情:
can('delete', Article, { 'comment.id': user.comment.id})
但是当我说 'Object literal may only specify known properties, and ''comment.id'' 在类型 'string[]'
中不存在
您可以在 https://casl.js.org/v5/en/advanced/typescript 上找到有用的“带点符号的嵌套字段”部分。简而言之,当你使用 for notation 和 typescript 一起定义条件时,你需要创建一个自定义类型:
type FlatArticle = Article & {
'comment.id': Article['comment']['id']
};
can<FlatArticle>('read', Article, { 'comment.id': 1 });
最后这样解决了:
export enum Action {
Manage = 'manage',
Create = 'create',
Read = 'read',
Update = 'update',
Delete = 'delete',
}
export type Subject = InferSubjects<typeof Article |
typeof Comment |
typeof User |
'all';
export type AppAbility = PureAbility<[Action, Subject]>;
export const AppAbility = Ability as AbilityClass<AppAbility>;
然后像这样定义规则:
createForUser(user: User) {
const { can, cannot, build } = new AbilityBuilder(AppAbility);
can(Action.Read, Article, { 'comment.id': 1 });
return build({
detectSubjectType: item => item.constructor as ExtractSubjectType<Subject>
});
}
我似乎无法使用条件规则访问嵌套对象。 如果文章的评论与用户具有相同的 ID,我希望用户有权删除文章。 这些只是一些编造的 类 来测试...
这是我的代码:
import { defineAbility, AbilityBuilder } from '@casl/ability';
import { Ability, AbilityClass, ExtractSubjectType, InferSubjects } from '@casl/ability';
export class Article {
static readonly modelName = "Article";
static readonly __typename = "Article";
constructor( id: number,
title: string,
content: string,
user: User,
comment: Comment) {
this.id = id
this.title = title
this.content = content
this.user = user
this.comment = comment
}
id: number
title: string
content: string
user: User
comment: Comment
}
export class User {
static readonly modelName = "User"
static readonly __typename = "User";
constructor (id: number,
name: string,
comment: Comment) {
this.id = id
this.name = name
this.comment = comment
}
id: number
name: string
comment: Comment
}
export class Comment {
static readonly modelName = "Comment"
static readonly __typename = "Comment";
constructor(id: number,
content: string,
authorId: number) {
this.id = id
this.content = content
this.authorId = authorId
}
id: number
content: string
authorId: number
}
type Action = 'create' | 'read' | 'update' | 'delete';
type Subjects = InferSubjects<typeof Article | typeof Comment| typeof User, true>;
export type AppAbility = Ability<[Action, Subjects]>;
export function createForUser(user: User) {
const { can, cannot, build } = new AbilityBuilder<
Ability<[Action, Subjects]>
>(Ability as AbilityClass<AppAbility>);
can('delete', Article, { comment: {id: user.comment.id}})
return build({
detectSubjectType: item => item.constructor as ExtractSubjectType<Subjects>
});
}
我用以下方法测试它:
const comment = new Comment(0, 'a', 0)
const user = new User(1, 'sd', comment);
const article = new Article(2, 'sd', 'asd', user, comment)
const ability = createForUser(user);
console.log(ability.can('delete', article))// false
我在某个地方看到我需要做这样的事情:
can('delete', Article, { 'comment.id': user.comment.id})
但是当我说 'Object literal may only specify known properties, and ''comment.id'' 在类型 'string[]'
您可以在 https://casl.js.org/v5/en/advanced/typescript 上找到有用的“带点符号的嵌套字段”部分。简而言之,当你使用 for notation 和 typescript 一起定义条件时,你需要创建一个自定义类型:
type FlatArticle = Article & {
'comment.id': Article['comment']['id']
};
can<FlatArticle>('read', Article, { 'comment.id': 1 });
最后这样解决了:
export enum Action {
Manage = 'manage',
Create = 'create',
Read = 'read',
Update = 'update',
Delete = 'delete',
}
export type Subject = InferSubjects<typeof Article |
typeof Comment |
typeof User |
'all';
export type AppAbility = PureAbility<[Action, Subject]>;
export const AppAbility = Ability as AbilityClass<AppAbility>;
然后像这样定义规则:
createForUser(user: User) {
const { can, cannot, build } = new AbilityBuilder(AppAbility);
can(Action.Read, Article, { 'comment.id': 1 });
return build({
detectSubjectType: item => item.constructor as ExtractSubjectType<Subject>
});
}