• 在nodejs中实现双重身份验证机制


    在nodejs中实现双重身份验证机制

    在这里插入图片描述

    双重身份验证(Two-factor authentication)是一种安全机制,它要求用户提供两种不同的身份验证因素来访问他们的帐户:密码和发送到他们的移动设备的验证码。在本文中,我们将一步步通过使用speakeasynodejs中实现双重身份验证。

    步骤1

    首先安装依赖项,我们需要安装expressspeakeasy

    npm install express speakeasy
    
    • 1

    步骤2

    创建一个express服务,并将其配置使用JSON中间件和静态资源中间件:

    const express = require('express');
    const app = express();
    
    app.use(express.json());
    app.use(express.static('public'));
    app.listen(3000, () => {
      console.log('Server started on port 3000');
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    步骤3

    创建一个用户模型User,用于在数据库中存储用户数据。在这个例子中,我们将使用一个简单的数组来存储用户数据:

    const users = [];
    
    class User {
      constructor(id, name, email, password, secret) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.password = password;
        this.secret = secret;
      }
    }
    module.exports = { users, User };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    步骤4

    创建一个POST请求的路由用于处理用户的注册操作。在此路由中,我们将为用户生成一个密钥并将其保存在数据库中。我们还会向用户发送一个二维码,用户可以扫描这些代码,以便将帐户添加到他们的应用程序中:

    const { users, User } = require('./user');
    const speakeasy = require('speakeasy');
    const QRCode = require('qrcode');
    
    app.post('/register', (req, res) => {
      const { name, email, password } = req.body;
      // 为用户生成新的密钥
      const secret = speakeasy.generateSecret({ length: 20 });
      // 保存用户数据
      const user = new User(users.length + 1, name, email, password, secret.base32);
      users.push(user);
      // 生成一个二维码供用户扫描
      QRCode.toDataURL(secret.otpauth_url, (err, image_data) => {
        if (err) {
          console.error(err);
          return res.status(500).send('Internal Server Error');
        }
        res.send({ qrCode: image_data });
      });
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    步骤5

    创建一个POST请求的路由用于处理用户的登录操作。在此请求中,我们将验证用户的凭证,并需要从用户的应用程序中获得验证码。我们将使用speakeasy来生成和验证这个验证码:

    const { users } = require('./user');
    const speakeasy = require('speakeasy');
    
    app.post('/login', (req, res) => {
      const { email, password, token } = req.body;
      const user = users.find(u => u.email === email);
      // 验证用户的凭证
      if (!user || user.password !== password) {
        return res.status(401).send('Invalid credentials');
      }
      // 核实用户的令牌
      const verified = speakeasy.totp.verify({
        secret: user.secret,
        encoding: 'base32',
        token,
        window: 1
      });
      if (!verified) {
        return res.status(401).send('Invalid token');
      }
      // 用户经过认证
      res.send('Login successful');
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    我们通过检查用户是否存在以及他们的密码是否与请求中提供的密码匹配来验证用户的凭证。

    如果用户的凭证有效,我们使用speakeasy 来验证二维码。我们传递用户的密钥编码(应该是base32 )、请求中提供的令牌和window: 1(代表令牌在当前和前一个时间段有效)。

    如果令牌无效,我们将返回一个401未经授权的状态码,其中包含消息"无效令牌"。

    如果令牌有效,我们将发送一个200OK的状态码,其中包含"成功登录"的消息。此时,用户将进行身份验证,并可以访问应用程序中受保护的资源。

    步骤6

    创建一个中间件来验证用户是否已经成功登录。

    const speakeasy = require('speakeasy');
    
    exports.requireToken = (req, res, next) => {
      const { token } = req.body;
      // Find the user with the given email address
      const user = users.find(u => u.email === req.user.email);
      // Verify the user's token
      const verified = speakeasy.totp.verify({
        secret: user.secret,
        encoding: 'base32',
        token,
        window: 1
      });
      if (!verified) {
        return res.status(401).send('Invalid token');
      }
      // 令牌有效,继续到下一个中间件或路由处理程序
      next();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    下面这个路由中添加了requireToken中间件,需要存在一个有效的2FA令牌才能继续使用:

    app.post('/protected', requireToken, (req, res) => {
      // 只有当用户的令牌有效时才会调用此路由处理程序
      res.send('Protected resource accessed successfully');
    });
    
    • 1
    • 2
    • 3
    • 4

    总之,双重身份验证机制(2FA)是一种强大的安全机制,它为用户帐户增加了额外的保护层。通过要求用户提供两个不同的身份验证因素,例如密码和发送到他们的移动设备的代码,2FA可以帮助防止未经授权访问敏感信息。

  • 相关阅读:
    微信小程序是否可以使用自建SSL证书?
    这款开源神器,让聚类算法从此变得简单易用
    2023-9-10 能被整除的数
    java计算机毕业设计医院远程诊断系统源程序+mysql+系统+lw文档+远程调试
    把简单留给用户,把复杂交给 AI
    上海万粒携手花王中国 「贝贝粒妙妙宝宝学步助手」正式上线
    被问到: http 协议和 https 协议的区别怎么办?别慌,这篇文章给你答案
    SpringSecurity入门和项目中使用
    Spring 事务失效的场景
    三、RabbitMQ消息的可靠投递
  • 原文地址:https://blog.csdn.net/qq_42880714/article/details/133896769