node.js(express.js)+mysql实现登录功能

文章目录

  • 前言
      • 实现步骤
  • 实现步骤
      • 一、检测登录表单的数据是否合法
        • (3)新建schema/user.js
        • (4)在routes/use.js中引入schema/user.js中的方法reg_login_schema,代码如下:
      • 二、根据用户名查询用户的数据
      • 三、判断用户输入的密码是否正确
      • 四、生成JWT 的 Token 字符串
  • 最终登录接口代码如下:
      • 五、在app.js中注册路由之前,配置解析token的中间件,为了指定那些接口不需要进行Token 的身份认证


前言

实现步骤

1.检测表单数据是否合法
2.根据用户名查询用户的数据
3.判断用户输入的密码是否正确
4.生成JWT 的 Token 字符串


登录接口完整代码如下:controllers/user.js文件

// 登录接口
var db = require("../utils/db");
// 导入密码加密
const bcrypt = require("bcryptjs");
// 导入jwt 包来生成token
const jwt = require("jsonwebtoken");
// 导入密钥
const config = require("../config");
exports.login = (req, res) => {
  // 获取客户端提交到服务器的用户信息
  const userinfo = req.body;
  // 定义sql语句,根据用户名查询用户的信息
  const sql = `select * from ev_users where username=?`;
  // 执行sql语句,根据用户名查询用户的信息
  db.query(sql, userinfo.username, (err, results) => {
    // 执行sql语句失败
    if (err) return res.cc(err);
    // 执行sql语句成功,但是获取到的数据条件不等于1
    if (results.length !== 1) return res.cc("登录失败!");
    // 判断密码是否和数据库中的密码是否一致
    // compareSync 第一个参数用户输入的,第二个参数数据库查询到的
    // 返回值为ture 一致,反之
    const compareResult = bcrypt.compareSync(
      userinfo.password,
      results[0].password
    );

    console.log("1", userinfo.password);
    console.log("2", results[0].password);
    if (!compareResult) {
      return res.cc("登录失败233");
    }
    // 生成jwt的token字符串
    // 清空用户信息的密码和头像
    const user = { ...results[0], password: "", user_pic: "" };
    console.log(user);
    // 对用户的信息进行加密,生成token字符串
    const tokenStr = jwt.sign(user, config.jwtSecretKey, {
      expiresIn: "10h", // token 有效期为10小时
    });

    // 将生成的token字符串响应给客户端
    res.send({
      status: 0,
      message: "登录成功!",
      // 为了方便客户端使用,在服务器端直接拼接上Bearer的前缀
      token: "Bearer"+ tokenStr,
    });
    // res.cc("ok");
  });
};

实现步骤

一、检测登录表单的数据是否合法

1)安装 jOi 包,为表单中携带的每个数据项,定义验证规则:

npm install joi

(2)安装 @escook/express-j01 中间件,来实现自动对表单数据进行验证的功能:

npm install @escook/express-joi
(3)新建schema/user.js
// 导入定义验证规则的包
// const joi = require("@hapi/joi");
const joi = require("joi");
/**
 * string()值必须是字符串
 * alphanum()值只能包含a-zA-ZO-9的字符串
 * min(length) 最小长度
 * max(length) 大长度
 * required() 值是必填项,不能为 undefined
 * pattern(正则表达式) 值必须符合正则表达式的规则
 */

// 定义用户名和密码的验证规则
const username = joi.string().alphanum().min(1).max(10).required();
const password = joi
  .string()
  .pattern(/^[\S]{6,12}$/)
  .required();
// 定义验证注册和登录表单数据的规则对象
exports.reg_login_schema = {
  body: {
    username,
    password,
  },
};
(4)在routes/use.js中引入schema/user.js中的方法reg_login_schema,代码如下:
var express = require("express");
var router = express.Router();
// 引入封装的获取验证码的方法
var unr_handler = require("../controllers/user");

// 1.导入验证数据的中间件
const expressJoi = require("@escook/express-joi");
//  2.导入需要的验证规则对象
const { reg_login_schema } = require("../schema/user");

// 新用户注册
// router.post("/regUser", expressJoi(reg_login_schema), unr_handler.regUser);
// router.post("/regUser", unr_handler.regUser);
// 登录
router.post("/login", expressJoi(reg_login_schema), unr_handler.login);
module.exports = router;

二、根据用户名查询用户的数据

var db = require("../utils/db");
// 导入密码加密
const bcrypt = require("bcryptjs");
// 导入jwt 包来生成token
const jwt = require("jsonwebtoken");
// 导入密钥
const config = require("../config");
// 登录接口
exports.login = (req, res) => {
  // 获取客户端提交到服务器的用户信息
  const userinfo = req.body;
  // 定义sql语句,根据用户名查询用户的信息
  const sql = `select * from ev_users where username=?`;
  // 执行sql语句,根据用户名查询用户的信息
  db.query(sql, userinfo.username, (err, results) => {
    // 执行sql语句失败
    if (err) return res.cc(err);
    // 执行sql语句成功,但是获取到的数据条件不等于1
    if (results.length !== 1) return res.cc("登录失败!");
    // res.cc("ok");
  });
};

三、判断用户输入的密码是否正确

// 导入密码加密
const bcrypt = require("bcryptjs");
exports.login = (req, res) => {
  // 获取客户端提交到服务器的用户信息
  const userinfo = req.body;
  // 定义sql语句,根据用户名查询用户的信息
  const sql = `select * from ev_users where username=?`;
  // 执行sql语句,根据用户名查询用户的信息
  db.query(sql, userinfo.username, (err, results) => {
    // 执行sql语句失败
    if (err) return res.cc(err);
    // 执行sql语句成功,但是获取到的数据条件不等于1
    if (results.length !== 1) return res.cc("登录失败!");
    // 判断密码是否和数据库中的密码是否一致
    // compareSync 第一个参数用户输入的,第二个参数数据库查询到的
    // 返回值为ture 一致,反之
    const compareResult = bcrypt.compareSync(
      userinfo.password,
      results[0].password
    );
    console.log("1", userinfo.password);
    console.log("2", results[0].password);
    if (!compareResult) {
      return res.cc("登录失败233");
    }
    // res.cc("ok");
  });
};

四、生成JWT 的 Token 字符串

1)在生成 Token 字符串的时候,一定要别除 密码 和 头像 的值

  // 清空用户信息的密码和头像
    const user = { ...results[0], password: "", user_pic: "" };

2)安装成成token的字符串包

npm 1 jsonwebtoken@8.5.1

3)在 /controllers/user.js 模块的头部区域,导入 jsonwebtoken 包:

// 导入jwt 包来生成token
const jwt = require("jsonwebtoken");

4)创建 config.js 文件,并向外共享加密和还原Token 的 jwtSecretKey 字符串:

// 全局的配置文件
module.exports = {
  // 加密和解密 token 的密钥
  jwtSecretKey: "itheima No1. ^_^",
};

5)将用户信息对象加密成 Token 字符串, 在controllers/user.js文件引入config.js

// 导入密钥
const config = require("../config");
const user = { ...results[0], password: "", user_pic: "" };
    console.log(user);
    // 对用户的信息进行加密,生成token字符串
    const tokenStr = jwt.sign(user, config.jwtSecretKey, {
      expiresIn: "10h", // token 有效期为10小时
    });
       // 将生成的token字符串响应给客户端
    res.send({
      status: 0,
      message: "登录成功!",
      // 为了方便客户端使用,在服务器端直接拼接上Bearer的前缀
      token: "Bearer"+ tokenStr,
    });

最终登录接口代码如下:

// 登录接口
var db = require("../utils/db"); 
// 导入密码加密
const bcrypt = require("bcryptjs");
// 导入jwt 包来生成token
const jwt = require("jsonwebtoken");
// 导入密钥
const config = require("../config");
exports.login = (req, res) => {
  // 获取客户端提交到服务器的用户信息
  const userinfo = req.body;
  // 定义sql语句,根据用户名查询用户的信息
  const sql = `select * from ev_users where username=?`;
  // 执行sql语句,根据用户名查询用户的信息
  db.query(sql, userinfo.username, (err, results) => {
    // 执行sql语句失败
    if (err) return res.cc(err);
    // 执行sql语句成功,但是获取到的数据条件不等于1
    if (results.length !== 1) return res.cc("登录失败!");
    // 判断密码是否和数据库中的密码是否一致
    // compareSync 第一个参数用户输入的,第二个参数数据库查询到的
    // 返回值为ture 一致,反之
    const compareResult = bcrypt.compareSync(
      userinfo.password,
      results[0].password
    );

    console.log("1", userinfo.password);
    console.log("2", results[0].password);
    if (!compareResult) {
      return res.cc("登录失败233");
    }
    // 生成jwt的token字符串
    // 清空用户信息的密码和头像
    const user = { ...results[0], password: "", user_pic: "" };
    console.log(user);
    // 对用户的信息进行加密,生成token字符串
    const tokenStr = jwt.sign(user, config.jwtSecretKey, {
      expiresIn: "10h", // token 有效期为10小时
    });

    // 将生成的token字符串响应给客户端
    res.send({
      status: 0,
      message: "登录成功!",
      // 为了方便客户端使用,在服务器端直接拼接上Bearer的前缀
      token: "Bearer"+ tokenStr,
    });
    // res.cc("ok");
  });
};

/utils/db文件代码

const mysql = require("mysql");
const db = mysql.createPool({
  host: "localhost", // 连接地址
  port: "3306", //端口号
  user: "root", //用户名
  password: "XXXXXXX", //密码
  database: "exapp2", //数据库名
});
module.exports = db;

在这里插入图片描述

五、在app.js中注册路由之前,配置解析token的中间件,为了指定那些接口不需要进行Token 的身份认证

1.安装解析 Token 的中间件:

npm i express-jwt@5.3.3

2). app.js

// 导入配置文件
const config = require("./config");
// 解析token的中间件
const expressJWT = require("express-jwt");
// 使用 unless({ path:[/^\/user\//] )) 指定哪些接口不需要进行 Token 的身份认证
// ps: path: [/^\/user/] 改成你自己的接口前缀path: [/^\/XXX/] 
app.use(
  expressJWT({ secret: config.jwtSecretKey }).unless({ path: [/^\/user/] })
);

3)在 app.js 中的 错误级别中间件 里面,捕获并处理 Token 认证失败后的错误:

// 定义表单验证失败的错误的中间件,并把验证失败的结果响应给客户端
// 错误中间件
app.use(function (err, req, res, next) {
  // 数据验证失败,instanceof判断
  if (err instanceof joi.ValidationError) {
    return res.cc(err);
  }
  // token身份认证失败后的错误
  if (err.name === "UnauthorizedError") return res.cc("身份认证失败");
  // 未知错误
  res.cc(err);
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/330714.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式-Stm32-江科大基于标准库的GPIO4个小实验

文章目录 一 、硬件介绍二 、实验:LED闪烁、LED流水灯、蜂鸣器提示2.1 需求1:面包板上的LED以1s为周期进行闪烁。亮0.5s,灭0.5s.....2.2 需求2: 8个LED实现流水灯 三、硬件介绍-按键开关、光敏电阻四、 实验 按键控制LED、光敏传感器控制蜂鸣器4.1 需求1…

Go 语言中高效切片拼接和 GO 1.22 提供的新方法

Table Contents 切片拼接的必要性基本拼接方法及其局限性使用 append 函数高效拼接的策略控制容量和避免副作用利用 Go 1.22 的新特性切片动态扩容的深入理解内存重新分配与数据迁移性能优化策略结论在 Go 语言中,切片拼接是一项常见的操作,但如果处理不当,可能会导致性能问…

【计算机网络】【新加坡南洋理工大学】【Computer Control Network】【广域网和局域网简介】【中英对照(自译)】

一、说明 仅供学习使用。 二、广域网(WAN)和局域网(LAN)简介

基于springboot+vue的在线拍卖系统(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

Android: alarm定时很短时,比如500ms,测试执行mPowerManager.forceSuspend()后,系统不会suspend

参考文档: https://blog.csdn.net/weixin_35691921/article/details/124961404 Android: alarm定时很短时,比如500ms,然后执行mPowerManager.forceSuspend()后,系统不会suspend,原因分析: static int ala…

软件测试|sqlalchemy relationship

简介 SQLAlchemy是一个流行的Python ORM(对象关系映射)库,它允许我们以面向对象的方式管理数据库。在SQLAlchemy中,relationship是一个重要的功能,用于建立表之间的关系。在本文中,我们将详细探讨relation…

渗透测试之Kali如何利用CVE-2019-0708漏洞渗透Win7

环境: 1.攻击者IP:192.168.1.10 系统: KALI2022(vmware 16.0) 2.靶机IP:192.168.1.8 系统:Windows 7 6.1.7601 Service Pack 1 Build 7601 已开启远程协助RDP服务开启了3389端口 问题描述: KALI 如何利用CVE-2019-0708漏洞渗透Win7 解决方案: 1.打开kali,msf搜索…

[足式机器人]Part2 Dr. CAN学习笔记- Kalman Filter卡尔曼滤波器Ch05

本文仅供学习使用 本文参考: B站:DR_CAN Dr. CAN学习笔记 - Kalman Filter卡尔曼滤波器 Ch05 1. Recursive Algirithm 递归算法2. Data Fusion 数据融合Covarince Matrix协方差矩阵State Space状态空间方程 Observation观测器3. Step by step : Deriatio…

在自定义数据集上训练 YOLOv8 进行目标检测

这是目标检测中令人惊叹的 AI 模型之一。在这种情况下,您无需克隆存储库、设置要求并配置模型,就像在 YOLOv5 及其之前的版本中所做的那样。 在 YOLOv8 中,不需要执行这些手动任务。您只需安装 Ultralytics 即可,我将向您展示如何…

mybatis----小细节

1、起别名 在MyBatis中&#xff0c;<typeAliases>元素用于定义类型别名&#xff0c;它可以将Java类名映射为一个更简短的别名&#xff0c;这样在映射文件中可以直接使用别名而不需要完整的类名。 下面是一个示例&#xff1a; 在mybatis核心配置文件中配置typeAliases标…

[go语言]输入输出

目录 知识结构 输入 1.Scan ​编辑 2.Scanf 3.Scanln 4.os.Stdin --标准输入&#xff0c;从键盘输入 输出 1.Print 2.Printf 3.Println 知识结构 输入 为了展示集中输入的区别&#xff0c;将直接进行代码演示。 三者区别的结论&#xff1a;Scanf格式化输入&#x…

“深度剖析Nginx的高级部署“

深度剖析Nginx的高级部署与优化技巧 引言1. Nginx基础概念1.1 Nginx简介1.1.1 什么是Nginx&#xff1f;1.1.2 Nginx的特点与优势 2. Nginx部署安装MySQL运行java 总结 引言 在现代网络架构中&#xff0c;Nginx作为一款高性能的开源Web服务器&#xff0c;广泛应用于反向代理、负…

个人网站制作 Part 8 添加电子邮件通知与社交媒体集成 | Web开发项目

文章目录 &#x1f469;‍&#x1f4bb; 基础Web开发练手项目系列&#xff1a;个人网站制作&#x1f680; 添加电子邮件通知&#x1f528;使用Nodemailer&#x1f527;步骤 1: 安装Nodemailer &#x1f680; 社交媒体集成&#x1f528;使用社交媒体API&#x1f527;步骤 2: 集成…

Springcloud+Vue智慧工地源码 AI智能识别

智慧工地解决方案 一、现状描述 建筑工程建设具有明显的生产规模大宗性与生产场所固定性的特点。建筑企业70%左右的工作都发生在施工现场&#xff0c;施工阶段的现场管理对工程成本、进度、质量及安全等至关重要。同时随着工程建设规模不断扩大&#xff0c;工艺流程纷繁复杂&…

通讯录(C语言版)(静态通讯录)

✨欢迎来到脑子不好的小菜鸟的文章✨ &#x1f388;创作不易&#xff0c;麻烦点点赞哦&#x1f388; 所属专栏&#xff1a;项目 我的主页&#xff1a;脑子不好的小菜鸟 文章特点&#xff1a;关键点和步骤讲解放在 代码相应位置 引言&#xff1a; 1.菜单 通讯录也如同游戏&…

pyspark 笔记:窗口函数window

窗口函数相关的概念和基本规范可以见&#xff1a;pyspark笔记&#xff1a;over-CSDN博客 1 创建Pyspark dataFrame from pyspark.sql.window import Window import pyspark.sql.functions as F employee_salary [("Ali", "Sales", 8000),("Bob&qu…

JFlash工具将多个Bin文件或hex文件合并成一个(app+bootloader)

开发过程中&#xff0c;会遇到需要将多个bin文件合并成一个bin文件&#xff0c;尤其是需要将bootloader文件和App文件合并成一个文件。 1.使用version6.8下载地址&#xff1a;https://www.segger.com/downloads/jlink/ 2.芯片运行的起始地址:J-Flash工具可以根据选择的芯片类型…

el-date-picker默认结束为当前时分秒

在element ui中的日期时间选择组件中默认是00:00,现在需求是点击默认结束时间为当前时分秒&#xff0c;查了很多资料写的都不准确 需求&#xff1a;实现日期时间组件可选择当前日期&#xff0c;比如当前是2024年01月17号下午17&#xff1a;21 那选中时必须结束时间为17&#x…

JQuery 操作Class滚动轮播展示效果

JQuery 操作Class滚动轮播展示效果 展示效果&#xff1a; 1.html <div class"list"><div class"item"><div class"icon"></div><div class"content">第一行xxxxxxxxx</div></div><div …