问题
I'm trying to use the 'roles' package available on Atmosphere but I can't get it to work with Accounts.onCreateUser(), I can get the example on github. When I register a user, I want to add a role to them, when I test whether the role is assigned, it's not picking it up.
Here's my code
/server/users.js
Accounts.onCreateUser(function(options, user){
var role = ['admin'];
Roles.addUsersToRoles(user, role);
return user;
});
/client/page.js
Template.hello.events({
'click input': function () {
var loggedInUser = Meteor.user();
if (Roles.userIsInRole(loggedInUser, ['admin'])) {
console.log("Hi Admin!");
}else{
console.log("Please Log In");
}
}
});
回答1:
If you look at the code being used in the Roles
package you will see that they use your passed in user/userId to perform a query on the user's collection (here, starting at line ~623):
try {
if (Meteor.isClient) {
// On client, iterate over each user to fulfill Meteor's
// 'one update per ID' policy
_.each(users, function (user) {
Meteor.users.update({_id: user}, update)
})
} else {
// On the server we can use MongoDB's $in operator for
// better performance
Meteor.users.update(
{_id: {$in: users}},
update,
{multi: true})
}
}
Since onCreateUser
is called before the user object is inserted into the collection (docs: The returned document is inserted directly into the Meteor.users collection), Roles
cannot find it when it performs the query.
In order to fix this you must wait until the user is inserted into the collection. If you look at the Roles
package all of their examples show this. Like here, (second example, comments added), along with many others:
// insert user and retrieve the id
id = Accounts.createUser({
email: user.email,
password: "apple1",
profile: { name: user.name }
});
// now we can verify that the user was inserted and add permissions
if (user.roles.length > 0) {
Roles.addUsersToRoles(id, user.roles);
}
Hope that shines some light on your issue. So basically just insert the user and then add the permissions after.
回答2:
To add things to a user document after it has been inserted by the accounts
package, try this pattern. Note, you must meteor add random
in order to generate a userId
, which is safe to do in this context.
Accounts.onCreateUser(function (options, user) {
// Semantics for adding things to users after the user document has been inserted
var userId = user._id = Random.id();
var handle = Meteor.users.find({_id: userId}, {fields: {_id: 1}}).observe({
added: function () {
Roles.addUsersToRoles(userId, ['admin']);
handle.stop();
handle = null;
}
});
// In case the document is never inserted
Meteor.setTimeout(function() {
if (handle) {
handle.stop();
}
}, 30000);
return user;
});
回答3:
I don't understand how to integrate Roles.addUsersToRoles with the onCreateUser function called when a user is created. It doesn't work when it's called within OnCreateUser as you've done, as you've found. But the example case of calling addUsersToRoles within a user creation loop doesn't seem applicable to the normal use case of a new user creating an account.
Instead, I just do:
Accounts.onCreateUser(function(options, user){
var role = ['admin'];
user.roles = role
return user;
});
回答4:
The accepted answer forces you to write boilerplate code for login logic given by meteor through accounts-ui/password. The other answers make assumptions about the underlying implementation and the timeout solution introduces a race condition.
Why not do this:
Accounts.onCreateUser(function(options, user) {
...
Meteor.setTimeout(function () {
Roles.addUsersToRoles(user._id, roles, group);
},0);
...
});
You effectively add the role after whatever it is that triggered the onCreateUser call and use alanning's api to add to roles. (Tested with meteor 1.0, roles 1.2.13)
回答5:
The issue here really comes down to looking for a post create user hook (which onCreateUser
is not).
It turns out, such a thing exists! It's called the postSignUpHook
.
https://github.com/meteor-useraccounts/core/blob/master/Guide.md#options
I found this from this SO answer:
https://stackoverflow.com/a/34114000/3221576
This is the preferred method for adding roles to a user created with the boilerplate UserAccounts package (i.e. if you're not rolling your own with Accounts.createUser
).
UPDATE
Ultimately I ended up using matb33:collection-hooks as per this comment:
https://github.com/alanning/meteor-roles/issues/35#issuecomment-198979601
Just stick that code in your Meteor.startup and things work as expected.
回答6:
I didn't want to rewrite logic given by Meteor's accounts packages, set the ID myself, or use setTimeout.
Instead I have Tracker code watching the Meteor.user()
call, which returns the user if logged in and null if not.
So, effectively, once a user has logged in, this code will check to see if they've been assigned a role and if they haven't add them.
I did have to use a Meteor method because I don't want roles to be messed with client side, but you can change that.
/* client */
Tracker.autorun(function () {
var user = Meteor.user();
if (user && !Roles.getRolesForUser(user).length) {
Meteor.call('addUserRole', user);
}
});
/* server */
Meteor.methods({
addUserRole: function (user) {
Roles.addUsersToRoles(user, user.profile.edmodo.type);
},
});
回答7:
I way I found to do this and it's pretty simple.
I am passing role as an array, so I used [role]
On client-side, when the user signs up:
var role = $(event.target).find('#role').val();
/*
* Add account - Client-Side
*/
Accounts.createUser(account, (error) => {
if (error) {
console.log(error);
} else {
// server-side call to add the user to the role
// notice Meteor.userId() and [role]
Meteor.call('assignUserToRole', Meteor.userId(), [role]);
// everything went well, redirect to home
FlowRouter.go('home');
}
});
In our meteor methods (I am using lodash intersect method to verify the role I want user to choose)
Meteor.methods({
// when a account is created make sure we limit the roles
assignUserToRole: (userId, roles) => {
check(userId, String);
check(roles, Array);
var allowedRoles = ['student', 'parent', 'teacher'];
if (_.intersection(allowedRoles, roles).length > 0) {
Roles.addUsersToRoles(userId, roles, 'user');
} else {
Roles.addUsersToRoles(userId, ['student'], 'user');
}
}
});
来源:https://stackoverflow.com/questions/22649600/unable-to-add-roles-to-user-with-meteor-using-roles-package