Meteor-Community-Packages / meteor-roles

Authorization package for Meteor, compatible with built-in accounts packages
http://meteor-community-packages.github.io/meteor-roles/
MIT License
921 stars 168 forks source link

Using Roles to check Admin in react-router #218

Closed dinhtungdu closed 5 years ago

dinhtungdu commented 8 years ago

How can I wait for user subscription in react-router? Currently, I have a function requireAdmin and pass it to onEnter to check if user is admin or not, it needs Meteor.user() but when I go to admin panel directly by url (or refreshing the admin page), Meteor.user() always return undefined.

I searched for this issue and I got that happens because the user subscription didn't ready at that time. I found some solution but they only apply for iron/flow router, not react-router.

Do anyone have a workaround on this. Any help is very appriciated! 💯

cocacrave commented 8 years ago

I'm also looking for a solution to the same problem.

fakenickels commented 8 years ago

I use to put my redirection logic within a react-komposer container, so I can wait the data and do the logic after it was loaded super easily.

jonasbarsten commented 7 years ago

@grsabreu Could you show an example please? Going on 5 hours banging my head against the wall.

jonasbarsten commented 7 years ago

I eventually solved it by adding a callback to the onEnter-function and waiting for the user-subscription:

const authenticateSecure = (nextState, replace, callback) => {

  // If no user, redirect to login
  if (!Meteor.loggingIn() && !Meteor.userId()) {
    replace({
      pathname: '/login',
      state: { nextPathname: nextState.location.pathname },
    });
  }

  // If user is admin, redirect to /admin
  Meteor.subscribe("currentUser", {
    onReady: function () { 
      if (Roles.userIsInRole(Meteor.userId(), ['super-admin', 'admin'])) {
        replace({
          pathname: '/admin',
          state: { nextPathname: nextState.location.pathname },
        });
      };
      callback();
    },
    onError: function () { 
      console.log("error"); 
    }
  });   
};

<Route path="/secure" component={SecureLayout}>
  <IndexRoute component={SecureDashboard} onEnter={authenticateSecure} />
</Route>
fakenickels commented 7 years ago

@jonasbarsten I write the composer like this:

// RedirNonAdmin.js
import { Roles } from 'meteor/alanning:roles';
import { Meteor } from 'meteor/meteor';
import React from 'react';
import {composeWithTracker} from 'react-komposer';
import _ from 'lodash';

function composer(props, onData){
  if(!Roles.userIsInRole(Meteor.userId(), 'admin')){
      props.history.replace('/');
  }

  onData(null, {});
};

export default composeWithTracker(composer);

then I simple wrap it in some component:

// Dashboard.js
import RedirNonAdmin from '../RedirNonAdmin'

@RedirNonAdmin
export default class Dashboard {...}