javascript - 生成新的验证 token

标签 javascript node.js strongloop loopback

我想知道如何创建一个方法,或者是否有一种方法可以仅使用电子邮件生成新 token 。我想在我的网站“发送新的验证电子邮件”中创建一个选项,用户只需要输入电子邮件即可。实际上我正在使用 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 模型,您可以做两件事。有些人喜欢添加一个新的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之间的关系,否则会出现合法用户访问错误等奇怪行为。

(注意:虽然这是一项相当多的工作,但我认为能够稍微轻松地向 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.调用verify方法,发送邮件

要发送验证电子邮件,您有几个选项。您可以:
  • 重复使用 User.verify()方法 ( located in the user.js model file ) 和默认 SMTP 电子邮件
  • 重复使用 User.verify()方法,但使用您自己的 Emailer(例如通过 API 发送)
  • 手工做所有事情,即自己生成 token ,将其保存到用户集合然后发送电子邮件,这基本上就是 User.verify()做。但是,这还需要您编写确认逻辑,这还需要更多工作。

  • User.verify() 与默认电子邮件

    要复用verify方法,需要生成verify链接(除了token部分,会由方法自己添加),配置选项,调用方法。
    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 等)。这个答案中的代码是从我正在处理的一个项目的几个部分中提取的,虽然它几乎完成了,但您需要验证没有丢失回调和其他拼写错误和编译器错误,并提供代码来搜索与提供的电子邮件相对应的用户对象(这很容易做到)。

    关于javascript - 生成新的验证 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40441368/

    相关文章:

    javascript - 如何从 Node.js 服务器读取 json 响应?

    javascript - 使用用户模型进行环回时出现 401 错误

    loopbackjs - 在 Strongloop Loopback 中创建多个

    javascript - 魔术日历,日期与使用 JS/jQuery 的日期不匹配

    python - 如何在Node JS中访问当前文件文件夹之外的文件

    javascript - 这两个字符串的区别(JavaScript)

    node.js - 多个 bash 脚本无法在生成的子进程中异步运行

    javascript - 警告 : overriding remoting type user loopback

    javascript - 将新项目添加到 Mongoose 的现有数组中

    javascript - Ajax/Json 错误 : "A circular reference was detected while serializing an object of type" when trying to bring a list