使用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-base
或accounts-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,而不会覆盖它。
答案 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。