Roles-based authorization package for Meteor - compatible with built-in accounts package.
Based off of the excellent meteor-roles library but modified to support nested roles and a more advanced access control mechanism.
### Contributors
Thanks to @maerF0x0, @nickmoylan and @mcrider!
The examples
directory contains Meteor apps which show off the following features:
- Server-side publishing with authorization to secure sensitive data
- Client-side navigation with link visibility based on user permissions
- 'Sign-in required' app with up-front login page using
accounts-ui
- Client-side routing
Run locally:
- install Meteorite
git clone https://github.com/deepwell/meteor-authorization.git
- either
*
cd meteor-authorization/examples/router
or *cd meteor-authorization/examples/mini-pages
mrt
- point browser to
http://localhost:3000
- User entries in the
Meteor.users
collection gain a new field namedauthItems
which is an array of strings corresponding to the user's roles and permissions. - A new collection
Meteor.authItems
contains a global list of defined auth item names. - The currently logged-in user's
authItems
field is automatically published to the client.
Add this smart package to your project:
- install Meteorite
mrt add authorization
Here are some potential use cases:
-- Server --
Add users to roles:
var users = [
{name:"Normal User",email:"normal@example.com",roles:[]},
{name:"View-Secrets User",email:"view@example.com",roles:['view-secrets']},
{name:"Manage-Users User",email:"manage@example.com",roles:['manage-users']},
{name:"Admin User",email:"admin@example.com",roles:['admin']}
];
_.each(users, function (user) {
var id;
id = Accounts.createUser({
email: user.email,
password: "apple1",
profile: { name: user.name }
});
if (user.roles.length > 0) {
AuthManager.addUsersToRoles(id, user.roles);
}
});
Check user roles before publishing sensitive data:
// server/publish.js
// Give authorized users access to sensitive data
Meteor.publish('secrets', function () {
if (AuthManager.userIsInRole(this.userId, ['view-secrets','admin'])) {
return Meteor.secrets.find();
} else {
// user not authorized. do not publish secrets
this.stop();
return;
}
});
Prevent non-authorized users from creating new users:
Accounts.validateNewUser(function (user) {
var loggedInUser = Meteor.user();
if (AuthManager.userIsInRole(loggedInUser, ['admin','manage-users'])) {
return true;
}
throw new Meteor.Error(403, "Not authorized to create new users");
});
-- Client --
Client javascript has access to some of the same AuthManager functions as the server with the addition of a isInRole
handlebars helper which is automatically registered.
Like all Meteor applications, client-side checks are a convenience, rather than a true security implementation since Meteor bundles the same client-side code to all users. Providing the AuthManager functions client-side also allows for latency compensation during Meteor method calls.
NOTE: Any sensitive data needs to be controlled server-side to prevent unwanted disclosure. To be clear, Meteor sends all templates, client-side javascript, and published data to the client's browser. This is by design and is a good thing. The following example is just sugar to help improve the user experience for normal users. Those interested in seeing the 'admin_nav' template in the example below will still be able to do so by manually reading the bundled client.js
file. It won't be pretty but it is possible. But this is not a problem as long as the actual data is restricted server-side.
To run tests:
cd meteor-authorization
meteor test-packages ./authorization
- point browser at http://localhost:3000/
NOTE: If you see an error message regarding "The package named authorization does not exist" that means you are either: a) in the wrong directory or b) left off the './' in front of 'authorization' in step 2.
Step 2 needs to be run in the main 'meteor-authorization' directory and the './' is needed because otherwise Meteor only looks in directories named 'packages'.