【问题标题】:Using onResetPasswordLink, onEnrollmentLink, and onEmailVerificationLink methods properly in Meteor在 Meteor 中正确使用 onResetPasswordLink、onEnrollmentLink 和 onEmailVerificationLink 方法
【发布时间】:2015-03-10 13:31:55
【问题描述】:

我想知道是否有人愿意提供一个流星垫或代码示例,以在 Meteor 中正确使用上面列出的方法之一(使用铁:路由器)。我很难理解这些方法究竟是如何与我的应用程序交互的,而且这些方法似乎足够新,以至于没有太多关于如何正确使用它们的好的文档。谢谢!

http://docs.meteor.com/#/full/Accounts-onResetPasswordLink

【问题讨论】:

    标签: meteor iron-router meteor-accounts


    【解决方案1】:

    根据文档:

    您可以使用以下函数构建您自己的用户界面,或使用 accounts-ui 包来包含用于基于密码登录的统包用户界面。

    因此,这些回调用于滚动您自己的自定义解决方案。不过,我建议使用以下软件包之一,accounts-entry 是我的首选解决方案:

    【讨论】:

    • 感谢芯片。我实际上是在尝试在我们的应用程序中推出自己的自定义解决方案。除了这些回调之外,这一切都在工作。我想了解这些是如何工作的,因为我现在这样做的方式似乎有点“hackish”。我的印象是这些回调将有助于清理该代码。如果我弄明白了,我会尝试在这里为其他所有人发帖。
    • @bgmaster - 好的,听起来不错。是否正在发送电子邮件?如果没有,我肯定会先让它工作。之后,我将根据文档在 client-side 文件中添加回调,然后添加 console.log 语句以查看它们何时触发。回调文档对示例恕我直言,但基本描述是有道理的,所以我认为关键是要发送电子邮件以进行进一步的故障排除。
    • 所以是的,正在发送电子邮件。我点击了链接,似乎一切正常,但我对“完成”回调及其运作方式感到困惑。查看上面提供的代码@stbailo 有很大帮助。据我了解,“完成”只是允许应用程序在登录时继续前进。我希望我可以通过“完成”运行重定向,或执行其他操作。
    【解决方案2】:

    这个方法是我写的,希望能给个很好的例子说明如何使用。

    它旨在与Accounts.sendResetPasswordEmailAccounts.resetPasswordhttp://docs.meteor.com/#/full/accounts_sendresetpasswordemailhttp://docs.meteor.com/#/full/accounts_resetpassword)结合使用。

    基本上,假设您想实现自己的帐户 UI 系统,而不是使用 accounts-ui 包或类似包。如果你想拥有一个密码重置系统,你需要三样东西:

    1. 一种使用密码重置链接发送电子邮件的方法
    2. 一种了解用户何时单击重置链接的方法
    3. 一种实际重置密码的方法

    以下是流程的工作方式:

    1. 用户点击了您页面上的“重置密码”链接
    2. 您找出是哪个用户(可能通过让他们输入他们的电子邮件地址),然后致电Accounts.sendResetPasswordEmail
    3. 用户点击刚刚收到的电子邮件中的重置密码链接
    4. 您的应用程序已加载并使用Accounts.onResetPasswordLink 注册回调
    5. 回调被调用是因为 URL 中有一个带有密码重置令牌的特殊片段
    6. 此回调可以显示一个特殊的 UI 元素,要求用户输入新密码
    7. 应用使用令牌和新密码调用Accounts.resetPassword
    8. 现在用户已登录并且他们有一个新密码

    这有点复杂,因为它是可能的最高级和自定义流程。如果您不想搞乱所有这些回调和方法,我建议您使用现有的帐户 UI 包之一,例如 accounts-uihttps://atmospherejs.com/ian/accounts-ui-bootstrap-3

    对于一些示例代码,请查看accounts-ui 包的代码:https://github.com/meteor/meteor/blob/devel/packages/accounts-ui-unstyled/login_buttons_dialogs.js

    【讨论】:

    • 所以我查看了 accounts-ui 代码,它有所帮助。我很感激你链接到那个。我正在为传递给回调的“完成”函数而苦苦挣扎。看起来这只是重新启用自动登录?我不确定这是做什么的,但是否需要从您的 UI 流程中调用它(在提交密码更改表单并运行 Accounts.resetPassword 之后)?我想将我的应用重定向到新路线,但如果我这样做了,稍后调用“完成”似乎变得越来越困难。
    • “自动登录”是每次您在新选项卡中打开流星应用程序时都会发生的过程 - 它会在本地存储中查找现有登录信息。对于重置密码流程,我们不希望使用现有登录,因为这样您可能会在登录帐户 B 的同时重置帐户 A 的密码,这可能会造成混淆。如果用户想要取消密码重置流程,并且您想要继续正常的自动登录过程,完成回调很重要。
    【解决方案3】:

    好的,所以我将在这里发布我最终学习和做的事情,以便其他人可以将其用作参考。我也会尽力解释正在发生的事情。

    从其他 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;
      }
    });
    

    希望这对尝试构建自己的自定义身份验证表单的其他人有所帮助。其他答案中提到的包在许多情况下都很棒,但有时您需要通过包无法获得的额外自定义。

    【讨论】:

    • 哇,好答案!您对如何更好地记录这一点有任何想法吗?文档很难推理,因为有很多不同的 Accounts 方法,可能不清楚如何一起使用它们。
    • 是的,我完全理解您对文档和不同方法的关注。我要澄清的两件主要事情是 1) done 函数的工作原理,以及是否需要将它传递给 Template.myTemplate.events 处理程序(可能提供代码示例),以及 2) 单击链接时,应用在根级别加载。
    【解决方案4】:

    这个问题已经过去一年了,但我刚刚提出了同样的问题。 按照您的解决方案,我发现您可以使用路由器中的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;
    });
    

    【讨论】:

      猜你喜欢
      • 2016-09-04
      • 1970-01-01
      • 2016-06-08
      • 2016-04-14
      • 1970-01-01
      • 2017-05-20
      • 2016-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多