Не удалось добавить роли для пользователя с помощью метеор, используя пакет "ролей"

Я пытаюсь использовать пакет 'role', доступный в Atmosphere, но я не могу заставить его работать с Accounts.onCreateUser(), я могу привести пример в github. Когда я регистрирую пользователя, я хочу добавить к ним роль, когда я проверяю, назначена ли роль, она не подбирает его.

Здесь мой код

/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

Если вы посмотрите на код, используемый в пакете Roles, вы увидите, что они используют ваш переданный в user/userId для выполнения запроса в пользовательской коллекции (здесь, начиная с строки ~ 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 $in operator for
    // better performance
    Meteor.users.update(
      {_id: {$in: users}},
      update,
      {multi: true})
  }
}

Так как onCreateUser вызывается до того, как пользовательский объект вставлен в коллекцию (docs: возвращенный документ вставляется непосредственно в коллекцию Meteor.users), Roles не может найти его при выполнении запроса.

Чтобы исправить это, вы должны подождать, пока пользователь не будет вставлен в коллекцию. Если вы посмотрите на пакет Roles, все его примеры показывают это. Например here (второй пример, комментарии добавлены), а также многие другие:

// 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);
}

Надеюсь, что светит свет на ваш вопрос. Таким образом, в основном просто вставьте пользователя, а затем добавьте разрешения после.

Ответ 2

Чтобы добавить вещи в пользовательский документ после того, как он был вставлен пакетом accounts, попробуйте этот шаблон. Обратите внимание: вы должны meteor add random генерировать userId, что безопасно делать в этом контексте.

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

Я не понимаю, как интегрировать Roles.addUsersToRoles с функцией onCreateUser, вызванной при создании пользователя. Он не работает, когда вы вызываете его в OnCreateUser, как вы это делали, как вы уже нашли. Но пример случая вызова addUsersToRoles в цикле создания пользователя не представляется применимым к обычному случаю использования нового пользователя, создающего учетную запись.

Вместо этого я просто делаю:

Accounts.onCreateUser(function(options, user){
  var role = ['admin'];
  user.roles = role
  return user;
});

Ответ 4

Принятый ответ заставляет вас написать шаблонный код для логина входа, заданный метеоритом через учетные записи - ui/password. Другие ответы делают предположения о базовой реализации, а решение о тайм-ауте вводит условие гонки.

Почему бы не сделать это:

Accounts.onCreateUser(function(options, user) {

    ...

    Meteor.setTimeout(function () {
        Roles.addUsersToRoles(user._id, roles, group);
    },0);
    ...
  
});

Ответ 5

Проблема здесь действительно сводится к поиску сообщения создать пользовательский крючок (который onCreateUser нет).

Оказывается, такая вещь существует! Он назывался postSignUpHook.

https://github.com/meteor-useraccounts/core/blob/master/Guide.md#options

Я нашел это из этого ответа SO:

fooobar.com/questions/208822/...

Это предпочтительный метод добавления ролей для пользователя, созданного с помощью шаблона UserAccounts (т.е. если вы не используете свой собственный Accounts.createUser).

ОБНОВЛЕНИЕ

В конечном итоге я закончил использование matb33: collection-hooks в соответствии с этим комментарием:

https://github.com/alanning/meteor-roles/issues/35#issuecomment-198979601

Просто вставьте этот код в свой Meteor.startup, и все будет работать так, как ожидалось.

Ответ 6

Я не хотел переписывать логику, заданную пакетами счетов Meteor, самостоятельно устанавливать идентификатор или использовать setTimeout.

Вместо этого у меня есть код Tracker, наблюдающий за вызовом Meteor.user(), который возвращает пользователя, если он зарегистрирован, и null, если нет.

Таким образом, эффективно, как только пользователь войдет в систему, этот код проверяет, назначена ли им роль, и если они не добавили их.

Мне пришлось использовать метод Meteor, потому что я не хочу, чтобы роли были запутаны на стороне клиента, но вы можете это изменить.

/* 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

Я так и сделал, и это довольно просто.

Я передаю роль как массив, поэтому я использовал [role]

На стороне клиента, когда пользователь подписывается:

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');
  }
});

В наших методах метеор (я использую метод lodash intersect для проверки роли, которую я хочу, чтобы пользователь выбирал)

  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');
      }
    }
  });