Meteor自定义登录错误:访问被拒绝

时间:2015-06-09 14:10:50

标签: authentication meteor meteor-accounts

使用meteor@1.1.6,基于帐户,帐户密码和Meteorhacks cluster

一点背景:

我正在编写一个网络应用程序,允许用户从我们的咖啡馆购买小吃作为Meteor的概念验证。这个应用程序分为集群内的两个服务:管理小吃和购买的咖啡馆服务,以及管理用户和认证的用户服务。我们希望分离,因为将来我们将有其他服务订阅同一组用户,我们不想在多个地方管理用户。

什么有用

用户使用LDAP凭据登录用户服务。如果存在名称不存在的Meteor用户帐户,则使用其ldap信息创建新帐户。这些帐户使用Meteor允许的默认属性发布。用户将获得一个默认的PIN码作为用于订阅服务的密码(目前他们无法更改)。

cafe应用程序在用户服务上订阅Meteor.users出版物,然后显示所有活动用户。由于咖啡馆应用程序设计为在平板电脑上运行,我们希望尽量减少打字,因此我们允许用户通过触摸用户名来选择自己的帐户。之后,为它们提供一个引脚键盘以输入其引脚(密码),该引脚将被散列并通过集群发送以在用户服务上进行验证。然后,用户服务调用Accounts._checkPassword来验证请求,并返回带有userId和/或任何错误的对象。我们正在使用名为loginWithPin的自定义登录方法,该方法与loginWithPassword基本相同。所有这一切都很美妙。

什么不起作用

当身份验证API返回结果时,会出现问题。一切都正确,直到您输入密码。我们的自定义方法loginWithPin始终返回错误,但奇怪的方法是输入正确的PIN。身份验证过程在用户服务层上传递并传回像{ userId: '...' }这样的对象,但自定义方法会以Access Denied为原因抛出403错误。

我假设返回带有userId的对象的自定义登录方法实际上会通过该id登录用户。那,我无法在accounts-baseaccounts-password中找到任何会导致403拒绝访问错误的地方。

TLDR

我的自定义loginWithPin方法在使用正确的引脚时会返回[403] Access Denied错误,但身份验证是在另一个应用的API上进行的,用户可以使用该方法进行身份验证。密码真的存在。

咖啡馆应用代码

的客户机/ enter_pin / enter_pin.js

//...
if ( //pin fully entered ) {
  Meteor.loginWithPin(password.value, function( err ) {
    if ( Meteor.user() ) {
      // login successful, route to cafe
      Router.go('/cafe');
    } else {
      console.error('An error occurred while logging in: ', err);

      // other stuff to reset pinpad
    }
  }
}

的客户机/ login.js

Meteor.loginWithPin = function( pin, callback ) {
  var username = Session.get('selectedUser');

  check(username, String);
  // hash pin before sending it across cluster connection
  pin = Package.sha.SHA256(pin);

  // send login request
  Accounts.callLoginMethod({
    methodArguments: [{
      user: {
        username: username
      },
      pin: pin
    }],
    userCallback: callback
  });
};

服务器/ login.js

Accounts.registerLoginHandler(function( request ) {
  // use runAsync here since login request is asynchronous and we want to pause execution until this returns
  var response = Async.runSync(function( done ) {
    ClusterConnection.call('authenticateUser', request.user.username, request.pin, function( err, res ) {
      if ( !err && !res.error ) {
        console.log('successful login');
        done(null, res);
      } else {
        console.log('unsuccessful login');
        done(null);
      }
    });
  });

  // this should be either { userId: '...' }, or null if an error is present
  return response.result;
});

服务API

服务器/ api.js

Meteor.methods({
  'authenticateUser': function( username, pin ) {
    check(username, String);
    check(pin, String);

    var user = Meteor.users.findOne({username: username});
    var password = {digest: pin, algorithm: 'sha-256'};
    return Accounts._checkPassword(user, password);
  }
});

如果Access Denied未定义,则client/enter_pin/enter_pin.js中发现的错误是Meteor.user()中发生的错误,因为登录尚未发生。但是,即使身份验证API成功返回其中包含userId的对象,也会触发此错误。

更新

cafe app server / cluster.js(我们连接到用户服务的地方)

Cluster.connect('mongodb://localhost:27017/service-discovery');
Cluster.register('cafe');

EmployeeConn = Cluster.discoverConnection('employees');
EmployeeConn.subscribe('employees');

Meteor.users = new Mongo.Collection('users', {connection: EmployeeConn});

我认为主要问题在于最后一行,因为我正在重新定义Meteor.users集合。但是,我不知道如何将我们从用户服务获得的数据同步到服务器上的Meteor.users,而不会覆盖它。

1 个答案:

答案 0 :(得分:1)

  

但是,我不知道如何将我们从用户服务获取的数据同步到服务器上的Meteor.users,而不会覆盖它。

构建Meteor以提供简单的SyncData工作流程。

例如,您可以为每个服务使用另一个单独的Collection,并引用Meteor.users集合。

然后您将订阅您需要的服务集合。

在您的Meteor.users中,您将有一个新字段:

pinBasedServices: [
  {
   service: 'cafe',
   pin: 'XXX',
   lastLogin: '',
   generatedHashTokenFromTheServiceToGetTheDataFrom:'somehash',
   /* whatever */
  },
  {
   service: 'cheeseCakeService',
   pin: 'XYZ',
   /* So on.. */
  }
]

我希望,我可以给你另一个思考方向,不必覆盖Meteor Collections。只需在它上面构建。

如果您希望以您需要的方式进行数据同步,您还可以观察Meteor Collections。