Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Structure role-management in meteor-app with alanning:roles

I need some advice for building a correct role schema and management in my meteor-app.

Structure

  • Im using alanning:[email protected] for adding role management functionallity to the app.
  • There are four different user-types: Admin, Editor, Expert and User.
  • Furthermore there are several modules with different content, i.e. Cars, Maths and Images. Every module is organized in an own meteor-package.
  • In every module there are several categories, which can be added dynamically by editors.

Categories in modules

Module is structured like this:

elementSchema = new SimpleSchema({ 
    element:    {type: String, optional: true}
});

Cars.attachSchema(new SimpleSchema({
    title:      { type: String },
    content:    { type: String },
    category:   { type: [elementSchema], optional: true },
});

As you can see, all available categories are inside of the Collection of the module.

Rights

  • Admin: Complete rights
  • Editor: Can edit elements in selected moduls (i.e. editor_1 can edit elements in Cars and Images but not for Maths)
  • Expert: Can get rights to a complete module or just to some categories of a module (i.e.) expert_1 can edit Images, but only the elements in category "Honda" and "Mercedes" in Cars; no editing to Maths)
  • User: No editing

This is how I do the authentification technically:

router.js

var filters = {
    authenticate: function () {
        var user;
        if (Meteor.loggingIn()) {
            this.layout('login');
            this.render('loading');
        } else {
            user = Meteor.user();
            if (!user) {
                this.layout('login');
                this.render('signin');
                return;
            }
            this.layout('Standard');
            this.next();
        }
    }
}
Router.route('/car/:_id', {
    name: 'car',
    before: filters.authenticate,
    data: function () {
        return { 
            cars: Cars.findOne({ _id: this.params._id }) 
        };
    }
});

template

<template name="car">
    {{#if isInRole 'cars'}}
        Some form for editing
    {{else}}
        <h1>Restricted area</h1>
    {{/if}}
</template>

I put this router.js to every package. Only change is the data function which uses the Collection of each package (Cars, Maths, Images).

Update: As 'Eliezer Steinbock' commented it is necessary to restrict acces to the mongoDB itself. But until now I only did that on the routes.

permissions.js

Cars.allow({
    insert: function(userId) {
        var loggedInUser = Meteor.user()
        if (loggedInUser && Roles.userIsInRole(loggedInUser, ['admin','editor'])) return true;
    },
    update: function(userId) {
        var loggedInUser = Meteor.user()
        if (loggedInUser && Roles.userIsInRole(loggedInUser, ['admin','editor'])) return true;
    }
});

My problems

1) My first problem is how to use roles and groups. What would be the best way for using groups? And the second problem is, that there are no fixed categories in the modules. Right now I have no idea for a useful role/group schema.

2) How do I check for the roles? As there are different roles which can get access: admin, editor and expert. Also I got the problem with these experts who just get access to defined categories of this module.

3) Wouldn't it be better to make the permission.js more general. I mean, is it possible to make a dynamic function, so I don't have to put everywhere the same code? How do I implement the roles in the permission.js in a useful way?

like image 218
user3848987 Avatar asked Sep 16 '15 12:09

user3848987


1 Answers

if the logic for the permissions is the same you could just define it once in permissions.js

App = App || {}; // We are using Namespaces, so you don't have to.. but it's good
App.Permissions = {
    insert: function(userId) {
        var loggedInUser = Meteor.user()
        if (loggedInUser && Roles.userIsInRole(loggedInUser, ['admin','editor'])) return true;
    },
    update: function(userId) {
        var loggedInUser = Meteor.user()
        if (loggedInUser && Roles.userIsInRole(loggedInUser, ['admin','editor'])) return true;
    }
}

And then you can use it for your Collections:

Cars.allow(App.Permissions); // Or
Cars.allow(App.Permissions.getPermissionsForGroup('cars'))

Define roles somewhere..

Roles

// Give user the role "editor" in "cars" group
Roles.addUsersToRoles(someUserId, ['editor'], 'cars');
Roles.addUsersToRoles(someOtherId, ['admin'], 'cars');

Which you can prepare in permissions.js like this:

Permissions

App = App || {}; 
App.Permissions = {
 insert: function(userId) {...},
 update: function(userId) {...},
 getPermissionsForGroup: function(group) {
    return {
       insert: function(userId, doc) {
          // Only admin can insert
          return Roles.userIsInRole(userId, "admin", group);
       },
       update: function(userId, doc, fields, modifier) {
          // Editor & Admin can edit
          return Roles.userIsInRole(userId, ["editor","admin"], group);
       },
       remove: function(userId, doc) {
          // Only admin can remove
          return Roles.userIsInRole(userId, "admin", group);
       }
    }    
}

In this example admins can insert and update.. and editors can only update, but insert.

Regarding the documentation of alanning:roles you define and use roles like this:

// Super Admin definition..
Roles.addUsersToRoles(superAdminId, ['admin'], Roles.GLOBAL_GROUP);

Roles.addUsersToRoles(joesUserId, ['manage-team','schedule-game'], 'manchester-united.com')
Roles.addUsersToRoles(joesUserId, ['player','goalie'], 'real-madrid.com')

Roles.userIsInRole(joesUserId, 'manage-team', 'manchester-united.com')  // => true
Roles.userIsInRole(joesUserId, 'manage-team', 'real-madrid.com')  // => false

Yeah, make sure, that the permission logic will be included before your Collection definition.. obviously :)

like image 178
webdeb Avatar answered Sep 27 '22 17:09

webdeb