生成新的验证令牌

Generate new verification token

我想知道如何创建一个方法,或者是否有一种方法可以仅通过电子邮件生成新令牌。我想在我的站点 "Send new verification email" 中创建一个选项,用户只需要在其中输入电子邮件。实际上我正在使用 Mandril,所以我正在使用自定义方式发送电子邮件和验证用户:

  function generateVerificationToken(context, user, callback) {
    const { req } = context;
    req.app.models.User.generateVerificationToken(user, (error, token) => {
      if (error) {
        return callback(error, null);
      }
      callback(null, token);
    });
  }

  User.afterRemote('create', (context, user, next) => {
    generateVerificationToken(context, user, (error, token) => {
      if (error) {
        return next(error);
      }
      user.verificationToken = token;
      user.save((error) => {
        if (error) {
          return next(error);
        }
        loopback.Email.send({
          to: user.email,
          template: {
            name: 'signup-confirm',
          },
          global_merge_vars: [{
              name: 'href',
              content:`http://localhost:3000/api/accounts/confirm?uid=${user.id}&token=${token}&redirect=http://localhost:4200/login/token-verification&verification=1`
          }]
        }, (error) => {
          next(error);
        });
      });
    });
  });

提前致谢!

(注意:这个问题有点棘手,因为它涉及到一些修改,虽然不是那么难,但可能需要对代码进行一些重构。另外,请参阅最后的警告说明。 )

1。覆盖用户模型

(注意:虽然您可以在另一个模型中执行此操作,但为了保持一致性,我发现最好在 User 中执行此操作,尽管还有更多工作要做。)

要覆盖用户模型,您可以做两件事。有些人喜欢添加一个新的 user 模型(小写)并在那里进行覆盖,但我个人更喜欢使用 Spencer Mefford's more elegant way of doing it.

你应该检查整个要点,因为还有很多事情要做,但总结一下,你需要创建一个新的引导脚本,最好使用以“0”开头的名称(引导脚本按字母顺序执行)订单,因此您需要在剩下的东西之前准备好模型),例如

server/boot/0-user-model-override.js

然后添加必要的样板:

module.exports = function (app) {      
    var User        = app.models.User;
    var Email       = app.models.Email;
    var Role        = app.models.Role;
    var RoleMapping = app.models.RoleMapping;
    var ACL         = app.models.ACL;

    /*
    * If this is an initial setup, create the ACL entry,
    * otherwise just configure the relationships 
    * (this needs to be done every time the server is started)
    */

    if(process.env.INIT_SETUP == "true"){
        ACL.create({
            model: 'User',
            property: 'customEndpoint1',
            accessType: 'EXECUTE',
            principalType: 'ROLE',
            principalId: '$everyone',
            permission: 'ALLOW'
          }, function (err, acl) { // Create the acl
            if (err) console.error(err);
        });
    }

    RoleMapping.belongsTo(User);
    RoleMapping.belongsTo(Role);
    User.hasMany(Role, {through: RoleMapping, foreignKey: 'principalId'});
    User.hasMany(RoleMapping, {foreignKey: 'principalId'});
    Role.hasMany(User, {through: RoleMapping, foreignKey: 'roleId'});

    // Add your custom endpoints
    User.customEndpoint1 = function(param1, cb) {...};
    User.remoteMethod('customEndpoint1',...){...};
};

样板文件基本上就在那里,因为我们需要手动添加一个 ACL 条目来设置权​​限,以允许任何人请求新的验证电子邮件。如果不这样做,by default the User model denies access by non-authenticated users

另外请注意,我们只在进行初始设置时在数据库中创建 ACL 条目,即我们只执行一次(除非您设置新的数据库)。

但是我们需要在每次启动服务器时配置User、Role和RoleMapping之间的关系,否则您会遇到有效用户的访问错误和其他奇怪的行为。

(注意:虽然这是一项相当多的工作,但我认为能够稍微轻松地向用户模型添加新功能将使您能够将用户管理保留在其所属的位置。)

完成此设置后,您现在可以执行以下操作:

POST https://myserver/api/Users/newVerificationEmail

2。创建端点以请求新的 link

要像添加任何其他模型一样添加端点:

User.newVerificationEmail = function(email, cb) {
  console.log("A new verification email was requested for: " + email);   
  cb(null);
};

User.remoteMethod(
  'newVerificationEmail',
  {
    accepts: [
      {arg: 'email', type: 'string'}
    ],
    http: {
      verb: 'post'
    }
  }
);

3。调用验证方法并发送邮件

要发送验证电子邮件,您有几种选择。您可以:

  • 重新使用 User.verify() 方法 (located in the user.js model file) 和默认的 SMTP 电子邮件程序
  • 重新使用 User.verify() 方法,但使用您自己的电子邮件程序(例如通过 API 发送)
  • 手动完成所有操作,即自己生成令牌,将其保存到用户集合中,然后发送电子邮件,这基本上就是 User.verify() 所做的。但是,这需要您还编写确认逻辑,这还需要更多工作。

User.verify() 使用默认电子邮件

要重新使用验证方法,您需要生成验证 link(令牌部分除外,该部分将由方法本身添加),配置选项,然后调用该方法。

User.newVerificationEmail = function(email, cb) {
  console.log("A new verification email was requested");
  var userModel = User.constructor;

  // Note: To get user.id you need to query the DB 
  // for the User instance with the requested email

  var verifyLink = 'https://' +
                      hostAddress + 
                      ':' + 
                      portNumber +
                      restApiRoot + 
                      '/Users/confirm' +
                      '?uid=' +
                      user.id + 
                      '&redirect=https://' + hostAddress + '/verified?user_id='+user.id;

  var options = {
      type: 'email',
      mailer: Email,
      to: user.email,
      from: 'sender@example.com',
      subject: 'My Email Subject',
      template: path.resolve(__dirname, '../views/verify.ejs'),
      user: user,
      verifyHref: verifyLink,
      host: myEmailHost,
      port: myEmailPort
  };

  user.verify(options, function(err, response) {

    if (err) {
      console.log(err);
    }
    console.log("Account verification email sent to " + options.to);
    cb(null);
  });

};

创建电子邮件验证模板

将发送的电子邮件是 options.template 中指定的电子邮件,即 server/views/verify.ejs

此文件应包含我们再次生成的验证 link。你可以添加任何你想要的 HTML,只要确保添加 verifyHref 变量:

Please click <a href="<%= verifyHref %>">this link</a> to verify your email

完成这些更改后,每当您向 api/Users/newVerificationLink

发出 POST 请求时,这应该会发送一封电子邮件

User.verify() 与自定义电子邮件

我还没有完成这个解决方案的实施,但它基本上涉及创建您自己的电子邮件连接器以使用您的提供商的 API(例如 Mandrill、Mailgun 等)和 passing this model in the options.mailer field


警告:我没有测试过这段代码,有几个变量值需要您自己指定(例如 hostAddressportNumberrestApiRoot , ETC)。这个答案中的代码是从我正在处理的一个项目的几个部分中提取出来的,虽然它几乎完成了,但您需要验证没有丢失的回调和其他拼写错误和编译器错误,并提供代码来搜索与提供的电子邮件对应的用户对象(这很容易做到)。