unable to add roles to user with meteor using 'roles' package

可紊 提交于 2019-12-20 09:36:56

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!