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:
- CASL 4.0 https://medium.com/dailyjs/casl-4-0-what-is-inside-7c43c969b7b8
- https://medium.com/dailyjs/managing-user-permissions-in-your-react-app-a93a94ff9b40
- https://dev.to/dwalsh01/managing-user-roles-in-react-using-casl-11f6
- https://dev.to/youssefzidan/react-manage-dynamic-permissions-using-casl-redux-12dj
- https://github.com/stalniy/casl-examples/issues/4 (ts issue)
- casl-react source: https://github.com/stalniy/casl/tree/master/packages/casl-react/src