React 应用程序中的 CASL 授权 "Can" 条件无效

CASL Authorisation in a React app "Can" conditions have no effect

我正在尝试在 React 应用程序中实现 CASL 授权,我认为我不太了解如何实现它。

标准的 Can 组件似乎可以与基本的 CRUD 操作一起使用,但我无法获得产生任何效果的条件。我想我错过了什么。

我目前的理论是我需要使用 TypeScript 而不是普通的 Javascript 来使整个事情正常进行。我目前不知道任何 TypeScript,我真的很想推进我的应用程序,而不是必须学习另一种语言。如果必须的话,我会学习 TypeScript,但我需要知道它是否值得这样做。下面是我到目前为止所构建内容的简化版本。

Example on Code Sandbox

预期行为 我希望该应用程序显示此人可以读取和创建事物记录。他们还应该能够更新或删除特定的 Apple 记录。

预期输出:
我可以看看东西
我可以创造一个东西
我可以更新这个苹果
我可以删除这个苹果

实际行为 它忽略与条件有关的任何事情,并允许对所有内容进行创建、读取、更新和删除。

实际输出:
我可以看看东西
我可以创造一个东西
我可以更新任何东西
我可以删除任何东西

主应用程序

import "./styles.css";
import ThingManager from "../components/ThingManager";
import AbilityContextComponent from "../components/AbilityContextComponent";

export default function App() {
  return (
    <div className="App">
      <AbilityContextComponent>
        <ThingManager />
      </AbilityContextComponent>
    </div>
  );
}

技能上下文组件 用于构建能力上下文并结束能力的生成

import React from "react";
import { AbilityContext } from "../src/Can";
import { defineAbility } from "@casl/ability";

class AbilityContextComponent extends React.Component {
  render() {
    const ability = defineAbility((can) => {
      can("read", "thing");
      can("create", "thing");
      can("update", "thing", { userId: 3 });
      can("delete", "thing", { userId: 3 });
    });

    return (
      <AbilityContext.Provider value={ability}>
        {this.props.children}
      </AbilityContext.Provider>
    );
  }
}

export default AbilityContextComponent;

这里生成了Can组件

import { createContextualCan } from "@casl/react";
import React from "react";

export const AbilityContext = React.createContext();
export const Can = createContextualCan(AbilityContext.Consumer);

终于可以使用“事物”授权的组件

import React from "react";
import { Can } from "../src/Can";

class ThingManager extends React.Component {
  render() {
    const thing = {
      Name: "Apple",
      Description: "this is an Apple",
      Colour: "Green",
      UserId: 3
    };

    return (
      <div>
        <h3>Manage your things here</h3>
        <Can I="read" a="thing">
          <p>I can look at things</p>
        </Can>
        <Can I="create" a="thing">
          <p>I can create a thing</p>
        </Can>
        <Can I="update" a="thing">
          <p>I can update any thing</p>
        </Can>
        <Can I="delete" a="thing">
          <p>I can delete any thing</p>
        </Can>
        <Can I="update" this={thing}>
          <p>I can delete this {thing.Name}</p>
        </Can>
        <Can I="delete" this={thing}>
          <p>I can delete any {thing.Name}</p>
        </Can>
      </div>
    );
  }
}

export default ThingManager;

我一直在寻找有关如何更改“主题”的信息,这是 CASL 对您尝试设置权限的事物的术语。在这种情况下,我称之为“东西”。

原来有很多方法可以检测主题类型。

Subject Type Detection

通常它们都涉及告诉 Can 组件传入的 object 的主题是什么。

基本方法是在传递给“this”的 object 上调用函数 subject

从“@casl/ability”导入主题,并像 subject("thing", apple)

Working version on CodeSandBox

import React from "react";
import { Can } from "../src/Can";
import { subject } from "@casl/ability";

class ThingManager extends React.Component {
  render() {
    const apple = {
      Name: "Apple",
      Description: "this is an Apple",
      Colour: "Green",
      UserId: 3
    };
    
    return (
      <div>
        <h3>Manage your things here</h3>
        <Can I="read" a="thing">
          <p>I can look at things</p>
        </Can>
        <Can I="create" a="thing">
          <p>I can create a thing</p>
        </Can>
        <Can I="update" a="thing">
          <p>I can update a thing</p>
        </Can>
        <Can I="delete" a="thing">
          <p>I can delete a thing</p>
        </Can>
        <Can I="update" this={subject("thing", apple)}>
          <p>I can delete this {apple.Name}</p>
        </Can>
        <Can I="delete" this={subject("thing", apple)}>
          <p>I can delete any {apple.Name}</p>
        </Can>
      </div>
    );
  }
}

export default ThingManager;

我对 Can 工作原理的理解也有点错误。您会在工作示例中注意到“我可以更新一个东西”和“我可以删除一个东西”文本仍在显示。这是因为一般的“Can I update a”和“Can I delete a”类型的组件都会显示它们的 children 只要用户可以 update/delete 至少一件事情。它并不是说“此用户可以访问所有内容”。