【发布时间】:2015-03-10 13:31:55
【问题描述】:
我想知道是否有人愿意提供一个流星垫或代码示例,以在 Meteor 中正确使用上面列出的方法之一(使用铁:路由器)。我很难理解这些方法究竟是如何与我的应用程序交互的,而且这些方法似乎足够新,以至于没有太多关于如何正确使用它们的好的文档。谢谢!
【问题讨论】:
标签: meteor iron-router meteor-accounts
我想知道是否有人愿意提供一个流星垫或代码示例,以在 Meteor 中正确使用上面列出的方法之一(使用铁:路由器)。我很难理解这些方法究竟是如何与我的应用程序交互的,而且这些方法似乎足够新,以至于没有太多关于如何正确使用它们的好的文档。谢谢!
【问题讨论】:
标签: meteor iron-router meteor-accounts
根据文档:
您可以使用以下函数构建您自己的用户界面,或使用 accounts-ui 包来包含用于基于密码登录的统包用户界面。
因此,这些回调用于滚动您自己的自定义解决方案。不过,我建议使用以下软件包之一,accounts-entry 是我的首选解决方案:
结合使用 accounts-password 和 accounts-ui
或使用 https://atmospherejs.com/joshowens/accounts-entry,尤其是如果您想要 Facebook、Twitter 等 OAuth 集成。要使用此包处理 电子邮件验证,请参阅this Github issue.
【讨论】:
这个方法是我写的,希望能给个很好的例子说明如何使用。
它旨在与Accounts.sendResetPasswordEmail 和Accounts.resetPassword(http://docs.meteor.com/#/full/accounts_sendresetpasswordemail 和http://docs.meteor.com/#/full/accounts_resetpassword)结合使用。
基本上,假设您想实现自己的帐户 UI 系统,而不是使用 accounts-ui 包或类似包。如果你想拥有一个密码重置系统,你需要三样东西:
以下是流程的工作方式:
Accounts.sendResetPasswordEmail
Accounts.onResetPasswordLink 注册回调
Accounts.resetPassword
这有点复杂,因为它是可能的最高级和自定义流程。如果您不想搞乱所有这些回调和方法,我建议您使用现有的帐户 UI 包之一,例如 accounts-ui 或 https://atmospherejs.com/ian/accounts-ui-bootstrap-3
对于一些示例代码,请查看accounts-ui 包的代码:https://github.com/meteor/meteor/blob/devel/packages/accounts-ui-unstyled/login_buttons_dialogs.js
【讨论】:
好的,所以我将在这里发布我最终学习和做的事情,以便其他人可以将其用作参考。我也会尽力解释正在发生的事情。
从其他 cmets 中可以看出,传递给 Accounts.on****Link 回调的“完成”函数是让我绊倒的主要部分。这个函数只做一件事——重新启用自动登录。值得注意的是,“完成”功能/自动登录是核心“帐户”包之一的一部分,不能修改。 'autoLogin' 用于一种特殊情况:用户 A 尝试在用户 B 当前登录的计算机上重置他或她的密码。如果用户 A 在提交新密码之前退出重置密码流程,则用户 B 将保持登录状态in. 如果用户 A 完成重置密码流程,则用户 B 注销,用户 A 登录。
accounts-ui 包中用于处理“完成”的模式,以及我最终所做的,将“完成”分配给一个变量,然后可以将其传递给您的模板事件处理函数,并在您重置密码后运行逻辑是完整的。此变量分配需要在 Accounts.on****Link 回调中完成,但回调可以放置在任何顶级客户端代码中(只需确保正确分配变量的范围)。我只是把它放在我的 reset_password_template.js 文件的开头(到目前为止,我只是为了重置密码才这样做,但模式应该是相似的):
客户端/reset_password_template.js:
// set done as a variable to pass
var doneCallback;
Accounts.onResetPasswordLink(function(token, done) {
Session.set('resetPasswordToken', token); // pull token and place in a session variable, so it can be accessed later
doneCallback = done; // Assigning to variable
});
使用这些 on****Link 回调的另一个挑战是了解您的应用如何“知道”回调已被触发,以及应用需要做什么。由于 iron:router 与 Meteor 紧密集成,很容易忘记它是一个单独的包。重要的是要记住,这些回调是为独立于 Iron:router 而编写的。这意味着当单击发送到您的电子邮件的链接时,您的应用程序将在根级别 ('/') 加载。
***旁注 - StackOverflow 上还有一些其他答案提供了与 Iron:router 集成的方法,并为每个链接加载特定路由。对我来说,这些模式的问题是它们看起来有点老套,不符合“流星”的方式。更重要的是,如果核心 Meteor 团队决定改变这些注册链接的路径,这些路径就会中断。我尝试调用 Router.go('path');在 on****Link 回调中,但由于某种原因,这在 Chrome 和 Safari 中不起作用。我希望有一种方法来处理这些电子邮件链接中的每一个的特定路由,从而消除不断设置和清除会话变量的需要,但我想不出一个好的解决方案。
无论如何,正如@stubailo 在他的回答中所描述的那样,您的应用程序已加载(在根级别),并触发了回调。触发回调后,您就设置了会话变量。您可以使用此会话变量通过以下模式在根级别加载适当的模板:
client/home.html(或您的登录页面模板)
{{#unless resetPasswordToken}}
{{> home_template}}
{{else}}
{{> reset_password_template}}
{{/unless}}
有了这个,你需要在你的 reset_password_template.js 文件和 home.js 中处理一些事情:
client/home.js
// checks if the 'resetPasswordToken' session variable is set and returns helper to home template
Template.home.helpers({
resetPasswordToken: function() {
return Session.get('resetPasswordToken');
}
});
客户端/reset_password_template.js
// if you have links in your template that navigate to other parts of your app, you need to reset your session variable before navigating away, you also need to call the doneCallback to re-enable autoLogin
Template.reset_password_template.rendered = function() {
var sessionReset = function() {
Session.set('resetPasswordToken', '');
if (doneCallback) {
doneCallback();
}
}
$("#link-1").click(function() {
sessionReset();
});
$('#link2').click(function() {
sessionReset();
});
}
Template.reset_password_template.events({
'submit #reset-password-form': function(e) {
e.preventDefault();
var new_password = $(e.target).find('#new-password').val(), confirm_password = $(e.target).find('#confirm-password').val();
// Validate passwords
if (isNotEmpty(new_password) && areValidPasswords(new_password, confirm_password)) {
Accounts.resetPassword(Session.get('resetPasswordToken'), new_password, function(error) {
if (error) {
if (error.message === 'Token expired [403]') {
Session.set('alert', 'Sorry, this link has expired.');
} else {
Session.set('alert', 'Sorry, there was a problem resetting your password.');
}
} else {
Session.set('alert', 'Your password has been changed.'); // This doesn't show. Display on next page
Session.set('resetPasswordToken', '');
// Call done before navigating away from here
if (doneCallback) {
doneCallback();
}
Router.go('web-app');
}
});
}
return false;
}
});
希望这对尝试构建自己的自定义身份验证表单的其他人有所帮助。其他答案中提到的包在许多情况下都很棒,但有时您需要通过包无法获得的额外自定义。
【讨论】:
这个问题已经过去一年了,但我刚刚提出了同样的问题。
按照您的解决方案,我发现您可以使用路由器中的Session 变量和onAfterAction 挂钩来实现相同的目的,但使用路由:
Router.route('/', {
name: 'homepage',
action: function() {
if (Session.get('resetPasswordToken')) {
this.redirect('resetPassword', {token: Session.get('resetPasswordToken')});
} else {
this.render('home');
}
}
});
Router.route('/password/reset/:token', {
name: 'resetPassword',
action: function () {
this.render('resetPassword');
},
data: function() {
return {token: this.params.token};
},
onAfterAction: function () {
Session.set('resetPasswordToken', '');
}
});
当然,您还需要:
Accounts.onResetPasswordLink(function(token, done){
Session.set('resetPasswordToken', token);
doneResetPassword = done;
});
【讨论】: