Decentralized React App with CASL
1. Introduction
Some Frameworks support:
- @ casl / vue for Vue
- @ casl / react for React
- @ casl / angular for Angular 2+
- @ casl / aurelia for Aurelia
2. Configuration for Reactjs
Read more README.MD if not satisfied https://github.com/stalniy/casl/tree/master/packages/casl-react
There is also a sample project for react: https://github.com/stalniy/casl-react-example
a. Install packages
1 2 | npm install @casl/react @casl/ability |
b. Code
First we need to define two files, the ability.js
configuration file and the Can.js
component file. Where to put files, refer to How to structure React project by Mr. Dan Abramov .
Can.js
1 2 3 4 5 | import { createCanBoundTo } from "@casl/react" import ability from "./ability" export default createCanBoundTo(ability) |
This is a component to check if the current user has the rights and display what he / she wants. For example:
1 2 3 4 5 6 7 8 9 10 11 12 | import Can from './Can'; ... const Setting = ({ classes }) => ( <Buttons> <Can I="can" a="Shutdown"> {() => <Button onClick={this.handleShutdown} />} </Can> </Buttons> ); |
ability.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import { Ability } from "@casl/ability"; /** * Defines how to detect object's type: https://stalniy.github.io/casl/abilities/2017/07/20/define-abilities.html */ function subjectName(item) { if (!item || typeof item === "string") { return item; } return item.__type; } const ability = new Ability([], { subjectName }); export default ability; |
In this we need to input the array rules that the current user has no rights to the ability.
1 2 | ability.update([{"actions":"can","subject":["Shutdown"]}]) |
c. Integrated into the project
As explained above, we can hardcode permissions for each role or get it from the server after login
* Method 1:
Define a function and return and array rules
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | function defineRulesFor(user) { const { role } = user; const { can, rules } = AbilityBuilder.extract(); can("view", "Profile"); switch (role) { case USER_ROLES.TECHNICIAN: break; case USER_ROLES.SALON_MANAGER: break; case USER_ROLES.SALON_OWNER: can("reschedule", "Booking"); can("delete", "Booking"); break; case USER_ROLES.SUPPLIER: break; default: break; } return rules; } |
* Method 2:
Can retrieve data remote after login and pass to ability
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import React, { Component } from 'react' import ability from './ability' export class LoginComponent extends Component { login(event) { event.preventDefault() const { email, password } = this.state return fetch('path/to/api/login', { method: 'POST', body: JSON.stringify({ email, password }) }) .then(response => response.json()) .then(session => ability.update(session.rules)) } render() { return ( <form onSubmit={this.login.bind(this)}> ... </form> ) } } |
d. How to use View More :
1 2 3 4 | <Can I="create" a="Post"> {() => <button onClick={...}>Create Post</button>} </Can> |