Giter Site home page Giter Site logo

react-router-role-authorization's Introduction

npm version GitHub issues GitHub forks GitHub stars

Role-based authorization for react-router

React-Router Role Authorization is a library which can help you in controlling the access to specific routes depending on given user roles.

This is an implementation of the approach I previously described in my blog post: Role-based authorization using React-Router

Installation

This library is available as a NPM package, so you can install it as you would any other package:

npm install --save-dev react-router-role-authorization

Usage

React-Router Role Authorization library provides two React components: AuthorizedComponent and RoleAwareComponent. Please see below their purpose and how to utilize them in your application.

AuthorizedComponent

Thanks to AuthorizedComponent you can handle access to the route only for specific user roles. To do that, first you have to configure your routes:

ReactDOM.render((
  <Router history={browserHistory}>
    <Route component={AppContainer} path="/">
      <IndexRoute authorize={['user', 'admin']} component={HomeComponent} />
      <Route authorize={['admin']} component={RestrictedContainer}>
        <Route component={RestrictedPageComponent} path="/restricted" />
      </Route>
    </Route>
    <Route component={NotFoundComponent} path="/not-found" />
  </Router>
), document.getElementById('app'));

As you can see, all you have to do is to add the authorize attribute to the main routes of your application. By passing an array of user role names to this attribute, you can define which user roles make this route available.

Additionally you should define a "not found" route which is not restricted by any user role. This will be the place where the user will be redirected to if he will try to access an unavailable route.

The second thing you have to do is to use the AuthorizedComponent. As an example, let's take a look at the sample route configuration above and consider the RestrictedContainer component which is related to the /restricted route path. As you can see it is restricted by the admin user role:

import React from 'react';
import RouteHandler from './RouteHandler';
import { AuthorizedComponent } from 'react-router-role-authorization';
import Cookies from 'js-cookie';

class RestrictedContainer extends AuthorizedComponent {
  constructor(props) {
    super(props);

    this.userRoles = Cookies.get('user').roles;
    this.notAuthorizedPath = '/not-found';
  }

  render() {
    return (
      <div>
        <RouteHandler {...this.props} />
      </div>
    );
  }
}

export default RestrictedContainer;

Ok, so all you have to do to make it work is to inherit the RestrictedContainer component from AuthorizedComponent and set up two properties inside the constructor of the component.

The this.userRoles property should hold an array of user role names (array of strings - e.g. ['admin', 'mod']) which are usually obtained during the authentication process and are usually held in a suitable cookie (Cookies.get('user').roles is only an example - you can handle it however you like but basically it should return an array of user role names).

The this.notAuthorizedPath property is intended to be set to the path name of the route where the user will be redirected in case of no access.

And that's it - from now on, all child routes of the RestrictedContainer component will be restricted by the admin user role.

Custom handling of unauthorized access

By default when a user with insufficient roles tries to access a component he is redirected to notAuthorizedPath defined in AuthorizedComponent. Sometimes you may want to, for example, log it to console etc.

You can achieve it by overriding method handleUnauthorizedRole(routeRoles, userRoles) from AuthorizedComponent.

import React from 'react';
import RouteHandler from './RouteHandler';
import { AuthorizedComponent } from 'react-router-role-authorization';
import Cookies from 'js-cookie';

class RestrictedContainer extends AuthorizedComponent {
  constructor(props) {
    super(props);

    this.userRoles = Cookies.get('user').roles;
    this.notAuthorizedPath = '/not-found';
  }
  
  handleUnauthorizedRole(routeRoles, userRoles){
    // handle unsuccessful authorization somehow
    console.log(`Route is available for roles: ${routeRoles}, but your roles are: ${userRoles}...`);
    
    // you should still redirect somewhere else if you want to prevent from accessing the restricted route ...
    // ... or just use the default behaviour by calling `super.handleUnauthorizedRole()`
    const { router } = this.context;
    router.push('/');
  }

  render() {
    return (
      <div>
        <RouteHandler {...this.props} />
      </div>
    );
  }
}

export default RestrictedContainer;

WARNING! Be careful - if you override the handleUnauthorizedRole method, it will stop redirecting to the notAuthorizedPath path. Instead, it will allow access to the restricted route so you have to prevent it on your own (by redirecting somewhere manually or calling super.handleUnauthorizedRole() to use the default behaviour).

RoleAwareComponent

The RoleAwareComponent component gives you the ability to show or hide the component depending on given user roles.

Its usage is very simple and similar to the AuthorizedComponent component:

import React from 'react';
import { RoleAwareComponent } from 'react-router-role-authorization';
import Cookies from 'js-cookie';

class BoxOne extends RoleAwareComponent {
  constructor(props) {
    super(props);

    this.allowedRoles = ['user'];
    this.userRoles = Cookies.get('user').roles;
  }

  render() {
    const jsx = (
      <div>
        Box One
      </div>
    );

    return this.rolesMatched() ? jsx : null;
  }
}

export default BoxOne;

The BoxOne component inherits from the RoleAwareComponent component. And again, the whole setup is done inside the constructor - this.allowedRoles is an array of user role names which make this component visible; this.userRoles is an array of user role names which the user has.

But this is not all. The component provides two methods: this.rolesMatched and this.rolesMatchedExact which can be used inside the render method of the component:

  • this.rolesMatched finds the intersection of the two arrays and returns true if at least one of the user roles is present among the available roles.
  • this.rolesMatchedExact checks if the available roles array has exactly the same items as the user roles array.

As you can see in the example above, you can use one of these methods to return the markup of the component or just null.

react-router-role-authorization's People

Contributors

burczu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-router-role-authorization's Issues

How can I add this on universal(isomorphic) react web apps?

I was trying to figure out a way but it doesn't seem to work for me if I try to put this on server side.

I am using this boilerplate.
https://github.com/erikras/react-redux-universal-hot-example/

In server.js, I added

class Profile extends AuthorizedComponent {
  render() {
    return (
      <div className="profile-container">
        <RouteHandler {...this.props} />;
      </div>
    );
  }
}

And in same file, I replaced

        <Provider store={store} key="provider">
          <ReduxAsyncConnect {...renderProps} />
        </Provider>
          <Profile routes={getRoutes(store)}>
            <Provider store={store} key="provider">
              <ReduxAsyncConnect {...renderProps} />
            </Provider>
          </Profile>

For starting, I modified routes.js as

      <Route path="about" component={About} authorize={['admin']}/>
      <Route path="login" component={Login} authorize={['employee']}/>
      <Route path="survey" component={Survey} authorize={['employee', 'admin']}/>
      <Route path="widgets" component={Widgets}/>

and Rest I've made RoleAwareComponent.js and AuthorizedComponent.js and RouterHandler.js
as mentioned in the article http://frontendinsights.com/role-based-authorization-using-react-router/

These things doesn't seem to work.

Can you please direct me if this is the correct way to add Role Based Authorization on server side?
I can give further info if needed.

Thanks

impersonation

does this manages impersonation? That is mangling with the rle field on the browser so that a user can take another role?

integrate with react-router v4

As the new version of react-router is completely rewriten, it would be nice to add support for this version of react-router. Or maybe it is completely unnecesary now?

NPM package is out of date and missing features

The NPM package for this project says that its latest release is 1.0.0, but it's missing the "custom handling of unauthorized access" feature that allows users to overload handleUnauthorizedRole.

I believe it's currently at 549efbe but the Github repo doesn't have any tags to validate the release.

Creating tags in Github and updating the NPM package would resolve these issues.

Update the dependency of react router to 3.xx

We were using react-router 3.0.2 and got this error (mismatching history.js) with react-router-role-authorization because it has a dependency to react-router 2 by ^2.5.1.

/node_modules/react-router/es/createRouterHistory.js Cannot read property 'name' of null

Could you upgrade the router to 3.xx?

react router Link component breaks authorization

I am facing a problem with the Link component of React router. If I try to visit a restricted route through Link like as: Profile the AuthorizedComponent fails to check if the route is permitted to the user or not. Any help would be appreciated.
Thanks

explicit permission check

Consider implementing approach given by andrewingram on reddit

his comment below:

A few notes:
I tend to avoid role-based permissions, because it creates a high maintenance burden. By this I mean that if you change your concept of what a role is and isn't allowed to do, it means you have to go over your entire codebase and fix all your checks. Explicit permission checks (eg 'can_edit_products') scale better. You can still use roles to represent buckets of permissions, but you should never check against roles directly.
I prefer decorating my components to inheriting a different component class. Using inheritance doesn't mesh nicely with the functional composition pattern you use elsewhere in a React codebase. I ended up with this: permissionsRequired('can_foo_bars')(MyComponent)
At one point I did try defining permissions in routes, but I didn't like the result. Your mileage may vary :)

Update to support React 15.5+

Current version of 1.1.3 doesn't support React greater than 15.5 that don't ship with proptypes.

index.js?36bf:206 Uncaught TypeError: Cannot read property 'array' of undefined

from dist.js line 216

return AuthorizedComponent;
	  }(_react2.default.Component), _class.propTypes = {
	    routes: _react.PropTypes.array.isRequired
	  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.