← Back
casl draft react typescript

CASL setup with react and typescript

Install #

npm i --save @casl/ability @casl/react

## Define abilities

At src/ability.ts:

import { Ability, AbilityBuilder, AbilityClass } from "@casl/ability";

type Actions = "manage" | "create" | "read" | "update" | "delete";
type Subjects = "Remix" | "Archive" | "Sound" | "all";

export type AppAbility = Ability<[Actions, Subjects]>;
const AppAbilityClass = Ability as AbilityClass<AppAbility>;

Define rules for a User role #

At src/ability.ts:

export type UserRole = "anonymous" | "user" | "admin";

function defineRulesFor(role: UserRole) {
const { can, rules } = new AbilityBuilder(AppAbilityClass);

switch (role) {
case "admin":
can("manage", "all");
break;
case "user":
can(["read"], "Remix");
can(["manage"], "Sound", {});
break;
case "anonymous":
can(["read"], "Remix");
can(["read"], "Archive");
can(["read"], "Sound");
break;
}

return rules;
}

Create and update abilities #

Some CASL boilerplate (still src/ability.ts) required to connect authentication with authorization:

export function createAbility(role: UserRole): AppAbility {
return new AppAbilityClass(defineRulesFor(role), {});
}

export function updateAbility(ability: AppAbility, role: UserRole): AppAbility {
ability.update(defineRulesFor(role));
return ability;
}

Add hooks and Can component #

src/hooks/useAbility.ts:

import { createContext } from "react";
import { useAbility as useCaslAbility } from "@casl/react";
import { AppAbility, createAbility } from "../ability";

// TODO: Journal - Not null
// https://stackoverflow.com/questions/42273853/in-typescript-what-is-the-exclamation-mark-bang-operator-when-dereferenci
// https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#non-null-assertion-operator
export const AbilityContext = createContext<AppAbility>(
createAbility("anonymous")
);

export function useAbility() {
// https://casl.js.org/v5/en/package/casl-react#imperative-access-to-ability-instance
// triggers re-render in the component where you use this hook when you update Ability rules
return useCaslAbility(AbilityContext);
}

src/components/Can.tsx:

import { createContextualCan } from "@casl/react";
import { AbilityContext } from "../hooks/useAbility";

export default createContextualCan(AbilityContext.Consumer);

Connect to authentication mechanism #

TODO


References: