首页 文章

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

提问于
浏览
4

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

一点背景:

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

What works

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

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

What doesn't work

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

我假设返回带有userId的对象的自定义登录方法实际上会通过该id登录用户 . 那个,我在 accounts-baseaccounts-password 中找不到任何会引发403 Access Denied错误的地方 .

TLDR

我的自定义 loginWithPin 方法在使用正确的引脚时返回 [403] Access Denied 错误,但身份验证正在另一个应用程序's API where the user'的密码实际生效 .


Cafe app code

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

Service 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的对象,也会触发此错误 .


UPDATE

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 回答

  • 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 . 只需 Build 它 .

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

相关问题