We are running a website and a backend data management system, both are meteor web servers.
The backend needs fetch data from the website. So they have to share one database, and the same "users" collection for both. That means one can register on the website and login to the backend, which is obviously unacceptable.
To distinguish users of the website and the backend, I choose package alanning/meteor-roles.
All the backend users will have roles ['backend', 'admin']
,
while website users haven't.
In "safe" environment, backend has its own user registration entry. Users registered there will be given above roles automatically.
Put the following codes into server side JavaScript files to achieve above goal (based on examples/rolesWithAccountsUI on meteor-roles):
var ROLE_NAME = 'editor';
var GROUP_NAME = 'backend';
Meteor.publish('mallData', function(){
if (Roles.userIsInRole(this.userId, ROLE_NAME, GROUP_NAME)) {
console.log('pass check');
return Mall.find();
} else {
console.log('not pass check');
this.stop();
return;
}
});
Meteor.startup(function () {
Accounts.onCreateUser(function (options, user) {
Roles.setRolesOnUserObj(user, ROLE_NAME, GROUP_NAME);
if (options.profile) {
user.profile = options.profile
}
return user;
});
});
Roles.setRolesOnUserObj = function (users, roles, group) {
if (!users) throw new Error ("Missing 'users' param")
if (!roles) throw new Error ("Missing 'roles' param")
if (group) {
if ('string' !== typeof group)
throw new Error ("Roles error: Invalid parameter 'group'. Expected 'string' type")
if ('$' === group[0])
throw new Error ("Roles error: groups can not start with '$'")
// convert any periods to underscores
group = group.replace(/\./g, '_')
}
// ensure arrays to simplify code
if (!_.isArray(users)) users = [users]
if (!_.isArray(roles)) roles = [roles]
// remove invalid roles
roles = _.reduce(roles, function (memo, role) {
if (role
&& 'string' === typeof role
&& role.trim().length > 0) {
memo.push(role.trim())
}
return memo
}, [])
// if roles is empty, quit
if (roles.length === 0) return
// ensure all roles exist in 'roles' collection
existingRoles = _.reduce(Meteor.roles.find({}).fetch(), function (memo, role) {
memo[role.name] = true
return memo
}, {})
_.each(roles, function (role) {
if (!existingRoles[role]) {
Roles.createRole(role)
}
})
// ensure users is an array of objects
_.each(users, function (user) {
if ('object' !== typeof user) {
throw new Error("Expected 'users' argument to be an object or array of objects")
}
})
// Set the roles on the actual user object
if (group) {
// roles is a key/value dict object
_.each(users, function (user) {
user.roles = {}
user.roles[group] = roles
})
} else {
// roles is an array of strings
_.each(users, function (user) {
user.roles = roles
})
}
}
Now any user outside 'backend' group, or without 'editor' role, can't get any data from server.
Unfortunately Internet is unsafe at all. So the registration entry has to be removed from the accounts-ui:
Meteor.startup(function () {
Accounts.config({
forbidClientAccountCreation : true
});
});
Now if you want give a website personnel rights to edit data through backend, first he should register on the website, then you define his role manually in mongo console:
> db.users.find({ "emails.0.address":"user@123.com" }, { "emails":1 })
> db.users.update({_id: "PM36t6eRmuC9oELdu"}, { $set: { roles: {"backend": [ "editor" ]} } })
First find the id of the user (here is "user@123.com") by his email address. Then add group and roles to the user (say the id of the user is "PM36t6eRmuC9oELdu").