生成新的验证令牌

时间:2016-11-05 17:49:48

标签: javascript node.js strongloop loopback

我想知道如何创建方法,或者是否有方法仅使用电子邮件生成新令牌。我想在我的网站“发送新的验证邮件”中创建一个选项,用户只需要发送电子邮件。实际上我正在使用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 个答案:

答案 0 :(得分:0)

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

1。覆盖用户模型

(注意:虽然你可以在另一个模型中执行此操作,但为了保持一致,我发现最好在User内执行此操作,即使还有更多工作要做。) < / p>

要覆盖用户模型,您可以执行两项操作。有些人喜欢添加新的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

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

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

(注意:虽然这是相当多的工作,但我认为能够在某种程度上轻松地向User模型添加新功能将允许您将用户管理保留在它所属的位置。)

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

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

2。创建端点以请求新链接

要添加端点,您可以像使用任何其他模型一样添加端点:

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集合,然后发送电子邮件,这基本上是User.verify()的作用。但是,这需要您编写确认逻辑,这是更多的工作。

User.verify(),默认电子邮件

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

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

此文件应包含我们再次生成的验证链接。您可以添加所需的任何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等)。这个答案中的代码是从我正在处理的项目的几个部分中提取的,虽然它几乎完成,但您需要验证没有丢失的回调和其他拼写错误和编译器错误以及提供代码来搜索与提供的电子邮件对应的用户对象(这很容易)。