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

news2024/12/27 4:20:15

文章目录

  • 前言
      • 实现步骤
  • 实现步骤
      • 一、检测登录表单的数据是否合法
        • (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);
});

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅析Redis①:命令处理核心源码分析(上)

写在前面 Redis作为我们日常工作中最常使用的缓存数据库,其重要性不言而喻,作为普调开发者,我们在日常开发中使用Redis,主要聚焦于Redis的基层数据结构的命令使用,很少会有人对Redis的内部实现机制进行了解&#xff0c…

C++:类与结构体的对比

2024年1月18日 内容来自The Cherno:C系列 -------------------------------------------------------------------------------------------------------------------------------- C中关于class与struct,几乎没有区别,只有一个关于“可见度”的区别…

Go 爬虫之 colly 从入门到不放弃指南

文章目录 概要介绍如何学习官方文档如何安装快速开始如何配置调试分布式代理层面执行层面存储层面存储多收集器配置优化持久化存储启用异步加快任务执行禁止或限制 KeepAlive 连接扩展总结如果想用 GO 实现爬虫能力,该如何做呢?抽时间研究了 Go 的一款爬虫框架 colly。 概要…

【前后端的那些事】15min快速实现图片上传,预览功能(ElementPlus+Springboot)

文章目录 Element Plus SpringBoot实现图片上传,预览,删除效果展示 1. 后端代码1.1 controller1.2 service 2. 前端代码2.1 路由创建2.2 api接口2.2 文件创建 3. 前端上传组件封装 前言:最近写项目,发现了一些很有意思的功能&…

SD-WAN组网设计原则:灵活、安全、高效

在实现按需、灵活和安全的SD-WAN组网方案中,我们必须遵循一系列关键的设计原则,以确保网络的可靠性和效率。通过以下几点设计原则,SD-WAN能够满足企业对灵活性、安全性和高效性的迫切需求。 灵活的Overlay网络互联 SD-WAN通过IP地址在站点之间…

appium之联动pycharm

前置条件: 1.java环境安装好了 2.android-sdk安装好(uiautomatorviewer 也可以把这个启动起来) 3.appium安装好 4.adb devices查看下设备是否连接 pycharm入门代码--固定写法 from appium import webdriver# 定义字典变量 desired_caps …

SpringMVC下半篇之异常处理器及日期转换器

3.异常处理器 如果不加以异常处理,错误信息肯定会抛在浏览器页面上,这样很不友好,所以必须进行异常处理。 3.1.异常处理思路 系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由…

线性代数基础【5】特征值和特征向量

第五章 特征值和特征向量 第一节、特征值和特征向量的基本概念 一、特征值和特征向量的理论背景 在一个多项式中,未知数的个数为任意多个,且每一项次数都是2的多项式称为二次型,二次型分为两种类型:即非标准二次型及标准二次型 注意: ①二次型X^T AX为非标准二次型的充分必…

在线扒站网PHP源码-在线扒站工具网站源码

源码介绍 这是一款在线的网站模板下载程序,也就是我们常说的扒站工具,利用它我们可以很轻松的将别人的网站模板样式下载下来,这样就可以大大提高我们编写前端的速度了!注:扒取的任何站点不得用于商业、违法用途&#…

02 MyBatisPlus核心功能之基于Mapper接口CRUD+基于Service接口实现CRUD

项目结构: 1.1 Insert方法 // 插入一条记录 // T 就是要插入的实体对象 // 默认主键生成策略为雪花算法(后面讲解) //返回值是影响条数 int insert(T entity);1.2 Delete方法 // 根据 entity 条件,删除记录 int delete(Param(…

【PAT甲级】1178 File Path(25分)[文件树,模拟,unordered_map]

问题思路: 在不断输入的过程中,可以通过层深和一个二维的vector数组来建立一棵树。即每输入一个节点,应当作为该节点上一层的最后一个节点的子孩子。用一个哈希value来指定节点的id,通过一个last记录每个节点id(此时作…

2023年移远车载全面开花,智能座舱加速进击

作为汽车智能化的关键组件,车载模组正发挥着越来越重要的作用。 移远通信进入车载模组领域近十年,已形成了完善的车载产品队列,不但在5G/4G车载通信、智能座舱、C-V2X车路协同等领域打造了一枝独秀的产品线,也推出了车规级Wi-Fi/蓝…

Verilog基础:强度建模(一)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 一、强度建模基础 Verilog HDL提供了针对线网信号0、1、x、z的精准强度建模方式,这样可以允许将两个线网信号进行线与操作从而更加精确地描述出硬件行…

【论文阅读】Deep Graph Contrastive Representation Learning

目录 0、基本信息1、研究动机2、创新点3、方法论3.1、整体框架及算法流程3.2、Corruption函数的具体实现3.2.1、删除边(RE)3.2.2、特征掩盖(MF) 3.3、[编码器](https://blog.csdn.net/qq_44426403/article/details/135443921)的设…

[python]裁剪文件夹中所有pdf文档并按名称保存到指定的文件夹

最近在写论文的实验部分,由于latex需要pdf格式的文档,审稿专家需要对pdf图片进行裁剪放大,以保证图片质量。 原图: 裁剪后的图像: 代码粘贴如下。将input_folder和output_folder替换即可。(x1, y1), (x2…

【Go面试向】rune和byte类型的认识与使用

【Go】rune和byte类型的认识与使用 大家好 我是寸铁👊 总结了一篇rune和byte类型的认识与使用的文章✨ 喜欢的小伙伴可以点点关注 💝 byte和rune类型定义 byte,占用1个字节,共8个比特位,所以它实际上和uint8没什么本质区别,它表示…

一文了解【完全合作关系】下的【多智能体强化学习】

处于完全合作关系的多智能体的利益一致,获得的奖励相同,有共同的目标。比如多个工业机器人协同装配汽车,他们的目标是相同的,都希望把汽车装好。 在多智能体系统中,一个智能体未必能观测到全局状态 S。设第 i 号智能体…

Nginx前后端分离部署springboot和vue项目

Nginx前后端分离部署springboot和vue项目,其实用的比较多,有的小伙伴对其原理和配置还一知半解,现在就科普一下: 1、准备后端项目 后端工程无论是微服务还是单体,一般最终都是jar启动,关键点就是把后端服…

vivado RTL运行方法检查、分析方法报告、报告DRC

运行方法检查 Vivado Design Suite提供基于超快设计的自动化方法检查使用“报告方法论”命令的FPGA和SoC(UG949)方法论指南。您可以生成关于打开、详细阐述、综合或实现的方法论报告设计对于详细设计,方法报告会检查XDC和RTL文件。对于有关使…