node.js+captchapng+jsonwebtoken实现登录验证示例

yizhihongxing

下面是详细的 "node.js+captchapng+jsonwebtoken实现登录验证示例" 的攻略:

一、背景

在网站开发中,登录是非常普遍的需求。而如何确保用户登录的安全性,是需要我们考虑的重要问题之一。本文将介绍如何使用 node.js、captchapng 和 jsonwebtoken 模块,实现基于验证码和 token 的登录验证。

二、前置知识

在继续阅读本文之前,需要你掌握以下知识:

  • node.js 环境的搭建和基础语法的学习;
  • HTTP 请求和响应的基本概念;
  • Express 框架的使用方法;
  • 安装和使用 captchapng 和 jsonwebtoken 模块。

三、具体实现

1. 实现验证码

为了防止机器人暴力破解密码,我们需要在登录界面加入验证码。captchapng 模块可以帮助我们生成验证码图片。

首先,我们需要安装 captchapng 模块:

npm install captchapng

然后,在路由中添加生成验证码图片的代码:

const captchapng = require('captchapng');
const express = require('express');
const router = express.Router();

router.get('/captcha', (req, res) => {
  const width = 80;
  const height = 30;
  const code = parseInt(Math.random() * 9000 + 1000);
  const p = new captchapng(width, height, code);
  p.color(0, 0, 0, 0); // 背景颜色
  p.color(80, 80, 80, 255); // 文字颜色

  const img = p.getBase64();
  const imgbase64 = Buffer.from(img, 'base64');

  res.writeHead(200, {
    'Content-Type': 'image/png'
  });
  res.end(imgbase64);
});

以上代码中,我们定义了 /captcha 路由,用于生成验证码。代码中,我们首先定义了验证码的宽度和高度、验证码的内容(四位数字);然后,使用 captchapng 模块生成 png 格式的图片,并设置了背景颜色和文字颜色;最后,将生成的图片以 base64 格式返回到浏览器端。

2. 实现登录验证

接下来,我们需要使用 jsonwebtoken 模块来实现登录验证。Jsonwebtoken 是一个令牌(token)生成器和解析器,可以帮助我们生成并验证令牌。

先安装 jsonwebtoken 模块:

npm install jsonwebtoken

接着,在路由中添加验证用户名、密码和验证码的代码:

const jwt = require('jsonwebtoken');
const express = require('express');
const router = express.Router();

router.post('/login', async (req, res) => {
  const { username, password, captcha } = req.body;
  if (captcha !== req.session.captcha) {
    res.status(400).json({ success: false, message: '验证码错误' });
    return;
  }

  // 根据实际情况,需要从数据库或其它数据源中获取用户信息
  const valid = username === 'admin' && password === '123456';
  if (!valid) {
    res.status(400).json({ success: false, message: '用户名或密码错误' });
    return;
  }

  const token = jwt.sign({ username }, 'secret', { expiresIn: '1h' });
  res.json({ success: true, token });
});

以上代码中,我们定义了 /login 路由,用于验证用户名、密码和验证码,并返回生成的 token。

在代码中,我们首先判断验证码是否正确,如果不正确,则返回错误提示;然后,根据实际情况,从数据库或其它数据源中获取用户信息,判断用户名和密码是否正确,如果不正确,则返回错误提示;最后,使用 jsonwebtoken 模块生成 token,并返回给浏览器端。

3. 实现 token 鉴权

登录验证完成后,我们需要在接下来的业务逻辑中,使用 token 进行鉴权。

const jwt = require('jsonwebtoken');
const express = require('express');
const router = express.Router();

router.get('/info', async (req, res) => {
  try {
    const token = req.headers.authorization.split(' ')[1];
    const decoded = jwt.verify(token, 'secret');
    const { username } = decoded;

    // 根据实际情况,需要从数据库或其它数据源中获取用户信息
    const user = { username, role: 'admin' };
    res.json({ success: true, user });
  } catch (e) {
    res.status(401).json({ success: false, message: 'Token 鉴权失败' });
  }
});

以上代码中,我们定义了 /info 路由,用于获取登录用户的信息。在代码中,我们首先从请求头中获取 token,然后使用 jsonwebtoken 模块对 token 进行鉴权,如果鉴权成功,则返回用户信息;否则,返回错误提示。

四、示例说明

为了更好地理解以上实现过程,我们将给出两个示例说明。

示例一:前后端分离应用

在前后端分离的应用中,前端和后端是分开部署的。前端发送请求到后端,后端返回 JSON 格式的数据,前端再进行处理和渲染。

以下是一个使用 Vue.js 和 Express 实现的前后端分离应用的示例:

前端首页代码:

<template>
  <div>
    <h1>我的网站</h1>
    <p v-if="!loginUser">请登录</p>
    <p v-if="loginUser">欢迎 {{ loginUser.username }}</p>
    <button v-if="!loginUser" @click="showLoginDialog = true">登录</button>
    <button v-if="loginUser" @click="logout">退出</button>
    <div v-if="showLoginDialog">
      <input type="text" v-model="username" placeholder="请输入用户名"/>
      <input type="password" v-model="password" placeholder="请输入密码"/>
      <input type="text" v-model="captcha" placeholder="请输入验证码"/>
      <img :src="'/api/captcha?' + Math.random()" @click="refreshCaptcha" />
      <button @click="login">登录</button>
    </div>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        loginUser: null,
        showLoginDialog: false,
        username: '',
        password: '',
        captcha: ''
      }
    },
    methods: {
      refreshCaptcha() {
        this.$refs.captchaImg.src = '/api/captcha?' + Math.random();
      },
      async login() {
        const { data } = await axios.post('/api/login', {
          username: this.username,
          password: this.password,
          captcha: this.captcha
        });
        if (data.success) {
          // 登录成功,将 token 存储到 localStorage 中
          localStorage.setItem('token', data.token);
          this.showLoginDialog = false;
          this.fetchUserInfo();
        } else {
          alert(data.message)
        }
      },
      async logout() {
        localStorage.removeItem('token');
        this.loginUser = null;
      },
      async fetchUserInfo() {
        const token = localStorage.getItem('token');
        if (token) {
          try {
            const { data } = await axios.get('/api/info', {
              headers: { Authorization: 'Bearer ' + token }
            });
            this.loginUser = data.success ? data.user : null;
          } catch (e) {
            console.error(e);
          }
        }
      }
    },
    mounted() {
      this.fetchUserInfo();
    }
}
</script>

后端代码:

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));

app.get('/api/captcha', (req, res) => {
  // 生成验证码图片
});

app.post('/api/login', (req, res) => {
  const { username, password, captcha }= req.body;
  // 验证用户名、密码和验证码
  // 生成 token 并返回
});

app.get('/api/info', (req, res) => {
  const { authorization } = req.headers;
  const token = authorization.split(' ')[1];
  // 鉴权 token,返回用户信息
});

app.listen(3000, () => {
  console.log('Server started on http://localhost:3000');
});

在以上示例中,我们定义了一个前端首页,在首页中实现了登录和注销功能。当用户登录成功后,将 token 存储到浏览器的 localStorage 中;在获取用户信息时,需要将存储在 localStorage 中的 token 从请求头中传递给服务器端。

示例二:基于 session 的应用

session 是另外一种实现用户登录验证的方式。以下是一个基于 session 实现的应用的示例。

前端代码:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>我的网站</title>
</head>
<body>
  <h1>我的网站</h1>

  <div>
    <p v-if="!loginUser">请登录</p>
    <p v-if="loginUser">欢迎 {{ loginUser.username }}</p>
    <button v-if="!loginUser" @click="showLoginDialog = true">登录</button>
    <button v-if="loginUser" @click="logout">退出</button>
    <div v-if="showLoginDialog">
      <input type="text" v-model="username" placeholder="请输入用户名"/>
      <input type="password" v-model="password" placeholder="请输入密码"/>
      <input type="text" v-model="captcha" placeholder="请输入验证码"/>
      <img :src="'/captcha?' + Math.random()" @click="refreshCaptcha" />
      <button @click="login">登录</button>
    </div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <script>
    new Vue({
      el: 'body',
      data: {
        loginUser: null,
        showLoginDialog: false,
        username: '',
        password: '',
        captcha: ''
      },
      methods: {
        refreshCaptcha() {
          this.$refs.captchaImg.src = '/captcha?' + Math.random();
        },
        async login() {
          const { data } = await axios.post('/login', {
            username: this.username,
            password: this.password,
            captcha: this.captcha
          });
          if (data.success) {
            // 登录成功,显示欢迎信息和注销按钮
            this.showLoginDialog = false;
            this.fetchUserInfo();
          } else {
            alert(data.message)
          }
        },
        async logout() {
          await axios.post('/logout');
          this.loginUser = null;
        },
        async fetchUserInfo() {
          const { data } = await axios.get('/user');
          if (data.success) {
            this.loginUser = data.user;
          }
        }
      },
      async mounted() {
        this.fetchUserInfo();
      }
    })
  </script>
</body>
</html>

后端代码:

const express = require('express');
const session = require('express-session');

const app = express();

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: false }
}));

app.get('/captcha', (req, res) => {
  // 生成验证码图片
});

app.post('/login', (req, res) => {
  const { username, password, captcha }= req.body;
  // 验证用户名、密码和验证码
  // 将用户信息存入 session 中
});

app.get('/user', (req, res) => {
  const { user } = req.session;
  if (!user) {
    res.json({ success: false, message: '请先登录' });
  } else {
    res.json({ success: true, user });
  }
});

app.post('/logout', (req, res) => {
  // 销毁 session
});

app.listen(3000, () => {
  console.log('Server started on http://localhost:3000');
});

在以上示例中,我们利用了 Express 的 session 中间件,来存储用户信息。具体地,当用户登录成功时,我们将用户信息存入 session 中;当获取用户信息时,我们从 session 中读取用户信息。当用户注销时,我们销毁 session。

五、结语

本文详细讲解了如何使用 node.js、captchapng 和 jsonwebtoken 模块,实现基于验证码和 token 的登录验证。示例代码同时也给出了如何在前后端分离应用和基于 session 的应用中,实现登录验证的方法。希望这篇文章能够对您有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:node.js+captchapng+jsonwebtoken实现登录验证示例 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • WebStorm ES6 语法支持设置&babel使用及自动编译(详解)

    WebStorm ES6 语法支持设置 & Babel 使用及自动编译 (详解) WebStorm 是目前市面上最为流行的前端开发 IDE 之一,同时也支持 ES6 语法的开发,本文将详细讲解 WebStorm 如何设置 ES6 语法支持和使用 Babel 自动编译。 设置 WebStorm ES6 语法支持 在 WebStorm 中开启 ES6 语…

    node js 2023年6月8日
    00
  • 详解JavaScript 为什么要有 Symbol 类型?

    下面是详解“详解JavaScript 为什么要有 Symbol 类型?”的完整攻略。 一、为什么要有 Symbol 类型? 在 JavaScript 中,对象的属性名通常是字符串类型的。当我们定义两个同名属性时,后一个属性会覆盖前一个属性。但是,有些场景需要我们定义一些唯一的属性名,避免重复。这时,Symbol 类型就可以派上用场了。Symbol 类型是一种…

    node js 2023年6月8日
    00
  • NodeJS遍历文件生产文件列表功能示例

    下面是关于“NodeJS遍历文件生产文件列表功能示例”的完整攻略。 前置知识 Node.js基础语法 文件系统(fs)模块的常用API 代码实现 实现遍历文件并生产文件列表,需要用到Node.js自带的文件系统模块(fs)。首先,我们需要引入fs模块。 const fs = require(‘fs’); 接着,定义一个函数readDirSync来遍历文件夹,…

    node js 2023年6月8日
    00
  • 我的Node.js学习之路(四)–单元测试

    下面是我的Node.js学习之路(四)–单元测试的完整攻略: 1. 什么是单元测试? 单元测试是针对软件系统中的最小可测试单元进行验证和检验的过程。在Node.js中,单元通常是指一个函数、一个方法或者一个模块。 单元测试的目的是在代码实现之前或者之后,尽早地发现代码中的问题,使得我们能够及早地进行修改和优化。通过单元测试,我们可以确保代码在各种情况下都能…

    node js 2023年6月8日
    00
  • JS密码生成与强度检测完整实例(附demo源码下载)

    下面来详细讲解这篇文章。 JS密码生成与强度检测完整实例(附demo源码下载) 1.密码生成 在正式开始之前,首先需要了解一下什么是密码生成。密码生成是指利用特定的算法和规则生成一定长度的随机字符串作为密码,提高密码的随机性和复杂度,从而防止密码被破解。 在这篇文章中,作者实现了一个非常简单的密码生成功能,代码如下: function generatePas…

    node js 2023年6月8日
    00
  • 微信js-sdk上传与下载图片接口用法示例

    好的。首先,需要明确一下微信js-sdk是指微信公众号提供的一套前端JS接口,可以让网页嵌入到微信客户端内部,从而实现与微信相关的功能接口调用。微信js-sdk中提供了图片上传和下载的接口,下面分别对两个功能进行详细讲解。 图片上传接口用法示例 步骤1:引入微信JS-SDK 在需要使用图片上传接口的页面中,需要先引入微信JS-SDK的相关代码,在<he…

    node js 2023年6月8日
    00
  • 简单了解node npm cnpm的具体使用方法

    Node.js是一个开源、跨平台的JavaScript运行环境。它可以在服务器端运行JavaScript代码,而不仅仅是在浏览器端。NPM全称Node Package Manager,是Node.js的包管理器。CNPM则是淘宝镜像的NPM镜像,它提供了更快的下载速度,特别是在中国大陆地区非常受欢迎。 Node.js的安装 首先,我们需要下载和安装Node.…

    node js 2023年6月8日
    00
  • 使用Meteor配合Node.js编写实时聊天应用的范例

    下面我将详细讲解如何使用Meteor配合Node.js编写实时聊天应用的步骤: 1. 准备工作 首先,我们需要安装Node.js和Meteor。Node.js的安装可以直接在官网上下载安装包进行安装,而Meteor则需先安装Meteor客户端,使用以下命令行进行安装: curl https://install.meteor.com/ | sh 2. 创建Me…

    node js 2023年6月8日
    00
合作推广
合作推广
分享本页
返回顶部