question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Understanding React, Redux, and CASL

See original GitHub issue

Hello,

I have been trying to wrap my head around CASL and its react package and I cannot really seem to get comfortable with it. I will explain what I am hoping to do with CASL in the hopes of getting an answer I can understand! I apologise if this has been asked before.

Essentially I have an application will use react and redux, with redux store holding the logged in user (see the reducer schema below). Role with either be blank, “researcher” or “admin”

{
  isLoggedIn: null,
  user: null,
  role: '',
  errorMsg: ''
}

Admins and researchers should be able to visit certain routes. (i.e. admin can visit ‘/add/proposal’ but the researchers cannot, and the researchers can visit (‘proposals/all’) but the admin cannot etc.)

Where I get lost when following examples is as follows:

import { AbilityBuilder } from 'casl'

/**
 * 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
}

export default AbilityBuilder.define({ subjectName }, can => {
  can(['read', 'create'], 'Todo')
  can(['update', 'delete'], 'Todo', { assignee: 'me' })
})

Basically the final lines lose me. I understand that Todo is the object for which the rule is applicable, but how would that apply for routes etc? What object goes in its place? Should I just place “Route” in place of Todo? What is the purpose of {assignee: 'me' } also?

I am aware you have a previous react redux question but again it doesn’t help me get it. Again, I apologise.

function defineRulesFor(auth) {
  const { can, rules } = AbilityBuilder.extract()

  can('delete', 'Post', { userId: auth.userId });

  return rules
}

The above code was taken from a previously answered redux question. Where ‘Post’ is the part I don’t understand.

A TLDR: I would like to know what to place where ‘Post’ and ‘Todo’ are above when creating the rules for certain user roles (admin and researcher) with the hope of using it to hide routes from one while showing for another. Essentially what is this object I am applying the rules to.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:11 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
dwalsh01commented, Mar 6, 2019

I have since implemented the following to solve the issue, if theres an improvement please let me know.

For the ability.js file I have the following:

/* eslint-disable no-underscore-dangle */
import { Ability, AbilityBuilder } from '@casl/ability';
import store from '../store/index';

// Defines how to detect object's type
function subjectName(item) {
  if (!item || typeof item === 'string') {
    return item;
  }
  return item.__type;
}

const ability = new Ability([], { subjectName });

let currentAuth;
store.subscribe(() => {
  const prevAuth = currentAuth;
  currentAuth = store.getState().currentUserReducer;

  if (prevAuth !== currentAuth) {
    ability.update(defineRulesFor(currentAuth));
  }
});

function defineRulesFor(auth) {
  const { can, rules, cannot } = AbilityBuilder.extract();
  if (auth.role === 'researcher') {
    can('view', 'Researcher', { userId: auth.user.id });
    cannot('view', 'Admin', { userId: auth.user.id });
  }
  if (auth.role === 'admin') {
    can('view', 'Admin', { userId: auth.user.id });
  }
  return rules;
}

export default ability;

Majority of this code taken from a previous redux question @stalniy answered.

Place your current user object from redux store where mine has currentUserReducer.

Within my routes.jsx file I then implement “hiding” routes by doing the following:

const Routes = () => (
  <Switch>
    <Route exact path="/" component={GridCards} />
    <Route path="/profile" component={Profile} />
    <Route
      exact
      path="/admin/proposals"
      render={props => (
        <Can I="view" a="Admin">
          {() => <AppProposalPage {...props} />}
        </Can>
      )}
    />

To ensure the admin can’t see something the researcher can, simply change the <Can/> component to a="Researcher"

Should the author of this package have any improvements I can edit/update my reply. Hope this helps someone!

1reaction
stalniycommented, Mar 4, 2019
Read more comments on GitHub >

github_iconTop Results From Across the Web

React, Manage Dynamic Permissions Using CASL & Redux.
In this article, I will show you how to manage permissions with CASL in the Front-End using React and Redux.
Read more >
How to manage dynamic permissions using CASL & Redux
CASL is a JavaScript library that allows you to manage the permissions of a user based on their role. Why handle permissions in...
Read more >
CASL React
This package allows to integrate @casl/ability with React application. It provides Can component that allow to hide or show UI elements based on...
Read more >
Implementing CASL with React and Redux - Stack Overflow
I will be implementing role based authentication for certain routes in my react application and came across CASL. I see they have a...
Read more >
Understanding Redux: A tutorial with examples
React components are defined as classes or functions with application state access i.e. classes extend React.Component , and functions use the ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found