无法使用“角色”包向带有流星的用户添加角色

Posted

技术标签:

【中文标题】无法使用“角色”包向带有流星的用户添加角色【英文标题】: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");
    
  
);

【问题讨论】:

【参考方案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 在评论 ***.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://***.com/a/34114000/3221576

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

更新

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

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

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

【讨论】:

这就是我一直在寻找的解决方案!

以上是关于无法使用“角色”包向带有流星的用户添加角色的主要内容,如果未能解决你的问题,请参考以下文章

使用 alanning:roles 构建流星应用程序中的角色管理

MVC 添加角色并将其添加到用户

如何使用带有 LDAP 身份验证的 Apache Shiro 添加角色授权

用户分配的角色仍然无法识别

Thymeleaf 无法显示用户的用户名和角色

无法添加角色,Discord.js