【问题标题】:unable to add roles to user with meteor using 'roles' package无法使用“角色”包向带有流星的用户添加角色
【发布时间】:2014-05-04 04:22:48
【问题描述】:

我正在尝试使用 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");
    }
  }
});

【问题讨论】:

    标签: javascript meteor roles atmosphere


    【解决方案1】:

    如果您查看 Roles 包中使用的代码,您会发现它们使用您传入的用户/用户 ID 对用户的集合执行查询(here,从 ~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})
      }
    }
    

    由于onCreateUser在用户对象插入集合之前被调用(docs返回的文档直接插入到Meteor.users集合中),Roles找不到它当它执行查询时。

    为了解决这个问题,您必须等到用户被插入到集合中。如果您查看Roles 包,他们的所有示例都显示了这一点。像here,(第二个例子,添加了cmets),还有很多其他的:

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

    希望对您的问题有所启发。所以基本上只是插入用户,然后添加权限。

    【讨论】:

    • 优秀的答案。我以前见过这个问题,并愿意接受建议。也许只是在文档中特别指出这一点?
    • @alanning 谢谢!是的,这可能会引起一些混乱。我个人建议在文档中添加一些内容。即使只是在气氛页面的 client 部分之后添加注释也可能会捕获其中一些情况。否则,希望人们会开始找到与之相关的 SO 帖子。
    • 使用accounts-ui创建的用户呢?
    • @Dan,@DoctorPangloss 的回答让你使用onCreateUser,这很方便。我们使用自己的自定义 Meteor 方法来创建用户,因此在我们的应用程序中,我们按照 @Firo 建议的方式进行操作。我添加了一个新函数示例,该函数直接在用户对象 here 上设置角色,但只有角色使用的 db 结构保持不变(正如 DP 在他的一个 cmets 中提到的那样),它才会起作用。跨度>
    • 下一个版本的角色可能会采用一个标志,让您指示用户角色应该直接在用户对象上更新,以便它们可以直接在 onCreateUser 中使用。没有计划什么时候会。
    【解决方案2】:

    我不明白如何将 Roles.addUsersToRoles 与创建用户时调用的 onCreateUser 函数集成。正如您所发现的,当您在 OnCreateUser 中调用它时,它不起作用。但是在用户创建循环中调用 addUsersToRoles 的示例似乎不适用于新用户创建帐户的正常用例。

    相反,我只是这样做:

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

    【讨论】:

    • 虽然这适用于角色,但如果您同时拥有角色和组,则它不起作用。通常你会得到这样的东西:"roles" : { "__global_roles__" : [ "admin" ] },
    • 如果'admin' 还没有在roles 集合中,这会起作用吗?这会将其添加到roles 集合中吗?
    【解决方案3】:

    要在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;
    });
    

    【讨论】:

    • 这比user.roles = ['admin'] 即dojomouse 的回答有什么优势?
    • @dojomouse 的回答对allaning:roles 的工作方式做出了假设。如果他们不将角色存储在字符串数组中怎么办?如果其他一些代码修改了角色怎么办?如果您更新roles 并且他添加了一种方法来做到这一点怎么办?在对 dojomouse 的解决方案的评论中,您实际上似乎是一个示例,说明如果直接修改此数组,您将 100% 破坏某些东西。这样,您就可以保证,只要addUsersToRoles 没有改变,您就不会再做其他事情了。
    • 这比 Joe 上面的回答复杂得多,它不需要手动设置用户 ID、添加另一个不必要的依赖项或尽可能多的代码行,尽管它提供了一个简洁的观察者模式发布 onCreateUser 可能需要的复杂功能。
    • 当您需要使用组时,此答案有效。 @alanning 在评论 stackoverflow.com/questions/22649600/… 中提到的另一个选项不适用于组。
    【解决方案4】:

    接受的答案迫使您为流星通过帐户-ui/密码给出的登录逻辑编写样板代码。 其他答案对底层实现进行了假设,超时解决方案引入了竞争条件。

    为什么不这样做:

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

    您有效地添加角色之后触发 onCreateUser 调用并使用 alanning 的 api 添加到角色。 (使用流星 1.0 测试,角色 1.2.13)

    【讨论】:

    • 这里使用setTimeout()函数有什么意义?
    • 在onCreateUser这一点上,用户实际上并没有被创建。由于 javascript 是一个单线程进程,Meteor.setTimeout 保证其中的函数在创建用户的当前线程之后调用。
    • 我认为Meteor.defer()setTimeout0 有一些优势,但我不能100% 确定这个优势是什么。 :)
    • 不,Meteor.defer() 只是语法糖,仅此而已。见github.com/meteor/meteor/issues/2176
    【解决方案5】:

    我不想重写 Meteor 的帐户包给出的逻辑,自己设置 ID,或者使用 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);
      },
    });
    

    【讨论】:

      【解决方案6】:

      我发现这样做很简单。

      我将角色作为数组传递,所以我使用了 [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');
            }
          }
        });
      

      【讨论】:

        【解决方案7】:

        这里的问题实际上归结为寻找 post 创建用户挂钩(onCreateUser 不是)。

        原来,这样的东西是存在的!它被称为postSignUpHook

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

        我从这个 SO 答案中找到了这个:

        https://stackoverflow.com/a/34114000/3221576

        这是向使用样板 UserAccounts 包创建的用户添加角色的首选方法(即,如果您不使用 Accounts.createUser 滚动自己的角色)。

        更新

        最终我根据这条评论使用了 matb33:collection-hooks:

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

        只需将该代码粘贴到您的 Meteor.startup 中,事情就会按预期工作。

        【讨论】:

        • 这就是我一直在寻找的解决方案!
        猜你喜欢
        • 2015-07-04
        • 2020-09-09
        • 2019-11-10
        • 2020-09-02
        • 1970-01-01
        • 2021-10-12
        • 1970-01-01
        • 2018-09-03
        • 2018-09-10
        相关资源
        最近更新 更多