lost9123193
lost9123193

Reputation: 11040

Authorizing Route for Multiple Roles in React

I'm following a tutorial for authenticating react routes and I can now allow users to access a route if authenticated is true.

routes.js

import React from 'react';
import { Route, IndexRoute,Redirect } from 'react-router';

import App from './app';
import requireAuth from '../Authentication/require_authentication';

import Dashboard from '../Dashboard';
import Managers from '../Managers';
import Guests from '../Guests';
import Login from '../Login';

export default (
  <Route path="/" component={App}>
    <IndexRoute component={requireAuth(Dashboard)} />
    <Route path="dashboard" component={requireAuth(Dashboard)} />    
    <Route path="advertisers" component={requireAuth(Managers)} />
    <Route path="properties" component={requireAuth(Guests)}/>
    <Route path="login" component={Login} />

  </Route>
);

require_authentication.js

/*HIGHER ORDER COMPONENT */
import React, { Component } from 'react';
import { connect } from 'react-redux';

export default function(ComposedComponent) {
  class Authentication extends Component {
    static contextTypes = {
      router: React.PropTypes.object
    }     

    componentWillMount() {
      if (!this.props.authenticated) {
        this.context.router.push('/login');
      }
    }

    componentWillUpdate(nextProps) {
      if (!nextProps.authenticated) {
        this.context.router.push('/login');
      }
    }          

    render() {
      return <ComposedComponent {...this.props} />
    }
  }

  function mapStateToProps(state) {
    return { authenticated: state.auth.authenticated };
  }

  return connect(mapStateToProps)(Authentication);
}

When a user logs in they have this as the state in the localStorage:

userId: 1, 
userName:"Bob",
roleName:"Manager"

I'm still fairly new to composed components but I'm wondering if there's a way to not only authenticate but prevent users with specific roles from accessing routes. Eg. Managers should only be able to see the Manager route and Dashboard. Guests can only see Dashboard and Guests.

Upvotes: 0

Views: 2751

Answers (1)

George Borunov
George Borunov

Reputation: 1582

It's definitely possible, you simply need to add a condition after checking authorization that would check if user's role allows to see the route it's trying to render, and if not it may redirect the user to a default route or a page that displays an error message.

Following the concept of your Higher Order Component in require_authentication.js, here's a modified version that should do what you want:

const checkPermissions = (userRole, router) => {
  if (userRole === "Manager") {
    if (!(router.isActive('/dashboard') ||
          router.isActive('/manager'))) {
      return false;
    }
  }
  return true;
};

export default function(ComposedComponent) {
  class Authentication extends Component {
    static contextTypes = {
      router: React.PropTypes.object
    }     

    componentWillMount() {
      if (!this.props.authenticated) {
        this.context.router.push('/login');
      } else if (!checkPermissions(this.props.user.role, this.context.router)) {
        this.context.router.push('/');
      }
    }

    componentWillUpdate(nextProps) {
      if (!nextProps.authenticated) {
        this.context.router.push('/login');
      } else if (!checkPermissions(this.props.user.role, this.context.router)) {
        this.context.router.push('/');
      }
    }          

    render() {
      return <ComposedComponent {...this.props} />
    }
  }

  function mapStateToProps(state) {
    return {
      authenticated: state.auth.authenticated,
      user: state.auth.user
    };
  }

  return connect(mapStateToProps)(Authentication);
}

An implementation of the checkPermission function may be different and more configurable, the one from the example is just to demonstrate the idea.

I assumed that you have an authorized user data in your state inside the auth object. It may be changed depend on where user's data is stored in fact.

Upvotes: 1

Related Questions