【问题标题】:how can i access nested properties for CASL conditions如何访问 CASL 条件的嵌套属性
【发布时间】:2023-03-06 10:26:02
【问题描述】:

我似乎无法使用条件规则访问嵌套对象。 如果文章的评论与用户具有相同的 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}) 但是当我说'对象文字可能只指定已知属性,''comment.id''在'string []'类型中不存在

【问题讨论】:

    标签: node.js typescript casl


    【解决方案1】:

    您可以在https://casl.js.org/v5/en/advanced/typescript 上找到有用的“带点表示法的嵌套字段”部分。总之,当你使用 for 表示法和 typescript 一起定义条件时,你需要创建一个自定义类型:

    type FlatArticle = Article & {
      'comment.id': Article['comment']['id']
    };
    
    can<FlatArticle>('read', Article, { 'comment.id': 1 });
    

    【讨论】:

    • 感谢您的评论,我知道这是一种方法,但我不“想要”再次定义每个属性。最终找到了解决方案。
    • 在打字稿中没有其他方法可以实现这一点。至少在 ts 4.1 之前使用字符串文字类型。属性路径在 ts 中一直是个问题
    • Casl 以某种方式做到了。看看我发布的答案,casl 设法将其展平。
    【解决方案2】:

    最终这样解决:

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

    【讨论】:

    • 我不清楚您在定义comment.id 时如何获得类型安全性,您能否展示一下您用于科目的类?
    • 我使用的类与问题中的类相同。使用此语法时,我没有收到警告/任何验证。但这是我唯一要做的事情。
    • 通过使用PureAbility,这是我能发现的主要区别,我在定义我的能力时也失去了所有类型安全......
    猜你喜欢
    • 2019-12-13
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    • 2016-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    相关资源
    最近更新 更多