node写登录

dart 复制代码
"dependencies": {
    "body-parser": "^1.20.2",
    "cors": "^2.8.5",
    "express": "^4.18.2",
    "jsonwebtoken": "^9.0.0",
    "md5": "^2.3.0",
    "mysql": "^2.18.1"
  }
dart 复制代码
const express = require('express')
const app = express()
app.listen(3001,()=>{
    console.log('serve is running at http://127.0.0.1:3001')
})

创建数据库连接池

dart 复制代码
 let db = mysql.createConnection({
     host:'127.0.0.1',
     user:'root',
     password:'123456',
     database:'books',
     port:3306
 })

 db.connect((err)=>{
     if(err) throw err;
     console.log('连接成功')    
 })

 setInterval(function(){
     db.query('select 1')
 },5000);

加粗样式

dart 复制代码
// 创建连接池
const pool = mysql.createPool({
    host: '127.0.0.1',
    user: 'root',
    password: '123456',
    database: 'books',
    connectionLimit: 10 // 设置连接池最大连接数
  });
  
  // 查询函数
  function query(sql, callback) {
    // 从连接池中获取一个连接
    pool.getConnection((err, connection) => {
      if (err) {
        callback(err, null);
      } else {
        // 执行查询
        connection.query(sql, (err, results) => {
          // 释放连接
          connection.release();
          callback(err, results);
        });
      }
    });
  }
  
  // 定时任务
  setInterval(() => {
    const sql = 'SELECT 1';
    query(sql, (err, results) => {
      if (err) {
        console.error(err);
      } else {
        // console.log('查询结果:', results);
      }
    });
  }, 5000);

在上面的代码中两种写法我们都设置了一个定时任务,这段代码是为了保持数据库连接处于活动状态,每隔5秒会向数据库发送一个请求,确保数据库连接不会因为长时间没有交互而被断开,这个技巧被称为"保活"

配置跨域请求和解析前端数据

以下配置表示允许所有的网址和方法请求

dart 复制代码
app.use((req, res, next) => {               //解决跨域问题,能够允许所有网址和方法的跨域处理
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
    if ('OPTIONS' === req.method) {
      res.sendStatus(200);
    } else {
      next();
    }
  });

配置解析前端传递的数据用到了body-parser这个包

dart 复制代码
const bodyParser = require('body-parser');
app.use(bodyParser.json())              //解析json
app.use(bodyParser.urlencoded({ extended: true }));             //解析客户端传递过来的参数 

登录接口实现

登录接口实现思路

首先接收前端请求的参数,从中解析出用户名和密码,先判断用户名和密码是否存在,不存在直接返回

如果用户名密码都存在,对密码进行md5加密,在进行数据库查询,没有找到返回用户名或密码错误

查询到数据说明,用户名密码正确生成token返回给客户端

dart 复制代码
// 登录接口
app.post('/login', (req, res) => {
    const { username, password } = req.body;

    if(!username || !password) res.json({ code:403,message: '用户名或密码不能为空' });
    // 进行MD5加密
    const md5Pwd = md5(password);
    // 查询数据库中是否存在该用户
    const sql = `SELECT * FROM user WHERE username='${username}' AND password='${md5Pwd}'`;
    query(sql, (err, result) => {
        if (err) throw err;
        if (result.length === 0) {
            res.json({
                code: 1,
                message: '用户名或密码错误'
            });
        } else {
            // 验证成功,生成token并返回
            const payload = {username: username}; // 按照需求设置payload
            const secretKey = '147258'; // 按照需求设置密钥
            const token = jwt.sign(payload, secretKey, {expiresIn: '1h'}); // 生成token,设置过期时间1小时

            // 将token返回给客户端
            res.json({
                token:token,
                code: 0,
                message: '登录成功'
            });
        }
    });
});

验证token的中间件

在所有路由之前定义一个中间件来验证token是否存在,以及token是否有效

dart 复制代码
const verifyToken = (req, res, next) => {
    // 获取请信息中的token
    const token = req.query.token;
    // 如果token不存在,则返回错误信息
    if (!token) {
      return res.json({ code:401,message: '未提供token' });
    }
    try {
      // 验证token是否有效
      const decoded = jwt.verify(token, '147258');
      // 将解码后的token信息保存到请求对象中
      req.user = decoded;
      next();
    } catch (err) {
      return res.json({ code:403,message: 'token验证失败' });
    }
  }

退出接口

退出接口需要在token验证有效后才可以请求,具体的操作就是删除token即可

dart 复制代码
app.post('/user/logout',verifyToken, (req, res) => {
    // 删除token
    res.clearCookie('token');
    res.json({
        code: 0,
        message: '退出成功'
    });
});

获取用户信息接口

从中间件中拿到解析出来的user对象,并拿到里面的username属性

根据该属性判断用户的角色,之后返回给前端,前端可以用来做权限判定

dart 复制代码
//获取用户信息接口
app.get('/user/getInfo',verifyToken,(req,res)=>{
    const username =req.user.username
    if(username==='admin'){
        res.json({
            code:200,
            roles:'admin',
            introduction: 'I am a super administrator',
            avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
            name: '超级管理员'
        })
    }else if(username === 'editor'){
        res.json({
            code:200,
            roles:'editor',
            introduction: 'I am an editor',
            avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
            name: '编辑'
        })
    }else{
        res.json({
            code:201,
            roles:'未找到改该角色'
        })
    }

})

增删改查功能

这些功能都需要登录后才可以操作,请求都需要携带token

dart 复制代码
// 查询
app.get('/books/getAll',verifyToken,(req, res) => {
    query('SELECT * FROM book', (err, results) => {
        if (err) throw err;
        res.json({code:0,message: '获取数据成功',data:results})
    })
})

// 新增
app.post('/books/add',verifyToken,(req, res) => {
    const {title, author, publisher, publish_date, price} = req.body
    query(`INSERT INTO book (title, author, publisher, publish_date, price) VALUES ('${title}', '${author}', '${publisher}', '${publish_date}', '${price}')`, (err, results) => {
        if (err) throw err;
        res.json({code:0,message: '新增成功', id: results.insertId})
    })
})

// 修改
app.put('/books/put/:id',verifyToken, (req, res) => {
    const {title, author, publisher, publish_date, price} = req.body
    query(`UPDATE book SET title='${title}', author='${author}', publisher='${publisher}', publish_date='${publish_date}', price='${price}' WHERE id=${req.params.id}`, (err, results) => {
        if (err) throw err;
        res.json({code:0,message: '修改成功', id: req.params.id})
    })
})

// 删除
app.delete('/books/delete/:id',verifyToken, (req, res) => {
    query(`DELETE FROM book WHERE id=${req.params.id}`, (err, results) => {
        if (err) throw err;
        res.json({code:0,message: '删除成功', id: req.params.id})
    })
})

这里token我直接就使用params方式传参,因为我测试环境的前端就是这样写的,也可以使用用header来传token,看自己的需求

到目前为止,一个完整的小案列就算完成了!

完整代码

以下是完整的代码,依赖需要自己安装,具体的版本前面有写过

dart 复制代码
const express = require('express')
const mysql = require('mysql')
const cors = require('cors')
const jwt = require('jsonwebtoken')
const md5 = require('md5')
const bodyParser = require('body-parser');
const app = express()
app.use(bodyParser.json())              //解析json
app.use(bodyParser.urlencoded({ extended: true }));             //解析客户端传递过来的参数 

app.use((req, res, next) => {               //解决跨域问题,能够允许所有网址和方法的跨域处理
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
    if ('OPTIONS' === req.method) {
      res.sendStatus(200);
    } else {
      next();
    }
  });
  


// let db = mysql.createConnection({
//     host:'127.0.0.1',
//     user:'root',
//     password:'123456',
//     database:'books',
//     port:3306
// })

// db.connect((err)=>{
//     if(err) throw err;
//     console.log('连接成功')    
// })

// setInterval(function(){
//     db.query('select 1')
// },5000);

// 创建连接池
const pool = mysql.createPool({
    host: '127.0.0.1',
    user: 'root',
    password: '123456',
    database: 'books',
    connectionLimit: 10 // 设置连接池最大连接数
  });
  
  // 查询函数
  function query(sql, callback) {
    // 从连接池中获取一个连接
    pool.getConnection((err, connection) => {
      if (err) {
        callback(err, null);
      } else {
        // 执行查询
        connection.query(sql, (err, results) => {
          // 释放连接
          connection.release();
          callback(err, results);
        });
      }
    });
  }
  
  // 定时任务
  setInterval(() => {
    const sql = 'SELECT 1';
    query(sql, (err, results) => {
      if (err) {
        console.error(err);
      } else {
        // console.log('查询结果:', results);
      }
    });
  }, 5000);
//这段代码是为了保持数据库连接处于活动状态,
// 它会每隔5秒钟向数据库发送一个select 1的查询请求,确保连接不会因为长时间没有交互而被断开。
// 这个技巧被称为"保活",可以让长时间运行的应用程序保持稳定的连接状态。

// 定义一个中间件来验证token,是否需要登录才可以操作
const verifyToken = (req, res, next) => {
    // 获取请信息中的token
    const token = req.query.token;
    // 如果token不存在,则返回错误信息
    if (!token) {
      return res.json({ code:401,message: '未提供token' });
    }
    try {
      // 验证token是否有效
      const decoded = jwt.verify(token, '147258');
      // 将解码后的token信息保存到请求对象中
      req.user = decoded;
      next();
    } catch (err) {
      return res.json({ code:403,message: 'token验证失败' });
    }
  }
  

// 登录接口
app.post('/user/login', (req, res) => {
    const { username, password } = req.body;

    if(!username || !password) return res.json({ code:403,message: '用户名或密码不能为空' });
    // 进行MD5加密
    const md5Pwd = md5(password);
    // 查询数据库中是否存在该用户
    const sql = `SELECT * FROM user WHERE username='${username}' AND password='${md5Pwd}'`;
    query(sql, (err, result) => {
        if (err) throw err;
        if (result.length === 0) {
            res.json({
                code: 1,
                message: '用户名或密码错误'
            });
        } else {
            // 验证成功,生成token并返回
            const payload = {username: username}; // 按照需求设置payload
            const secretKey = '147258'; // 按照需求设置密钥
            const token = jwt.sign(payload, secretKey, {expiresIn: '1h'}); // 生成token,设置过期时间1小时

            // 将token返回给客户端
            res.json({
                code: 200,
                token:token,
                message: '登录成功'
            });
        }
    });
});

//获取用户信息接口
app.get('/user/getInfo',verifyToken,(req,res)=>{
    const username =req.user.username
    if(username==='admin'){
      res.send({
        code:200,
        data:{
          roles:'admin',
          introduction: 'I am a super administrator',
          avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
          name: '超级管理员'
        }
          
       })
    }else if(username === 'editor'){
        res.json({
            code:200,
              roles:'editor',
              introduction: 'I am an editor',
              avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
              name: '编辑'
        })
    }else{
        res.json({
            code:201,
            roles:'未找到改该角色'
        })
    }

})

// 退出接口
app.post('/user/logout',verifyToken, (req, res) => {
    // 清除登录状态
    // 删除token
    res.clearCookie('token');
    res.json({
        code: 200,
        message: '退出成功'
    });
});


// 查询
app.get('/books/getAll',verifyToken,(req, res) => {
    query('SELECT * FROM book', (err, results) => {
        if (err) throw err;
        res.json({code:0,message: '获取数据成功',data:results})
    })
})

// 新增
app.post('/books/add',verifyToken,(req, res) => {
    const {title, author, publisher, publish_date, price} = req.body
    query(`INSERT INTO book (title, author, publisher, publish_date, price) VALUES ('${title}', '${author}', '${publisher}', '${publish_date}', '${price}')`, (err, results) => {
        if (err) throw err;
        res.json({code:0,message: '新增成功', id: results.insertId})
    })
})

// 修改
app.put('/books/put/:id',verifyToken, (req, res) => {
    const {title, author, publisher, publish_date, price} = req.body
    query(`UPDATE book SET title='${title}', author='${author}', publisher='${publisher}', publish_date='${publish_date}', price='${price}' WHERE id=${req.params.id}`, (err, results) => {
        if (err) throw err;
        res.json({code:0,message: '修改成功', id: req.params.id})
    })
})

// 删除
app.delete('/books/delete/:id',verifyToken, (req, res) => {
    query(`DELETE FROM book WHERE id=${req.params.id}`, (err, results) => {
        if (err) throw err;
        res.json({code:0,message: '删除成功', id: req.params.id})
    })
})

app.listen(3001,()=>{
    console.log('serve is running at http://127.0.0.1:3001')
})
相关推荐
杰哥的技术杂货铺5 天前
在 macOS 上管理 Node版本
macos·node·nvm
双普拉斯14 天前
微信小程序显示后台文章副文本,图片和视频正常显示
前端·微信小程序·node
珍珠是蚌的眼泪25 天前
Kubernetes
kubernetes·k8s·node·container·pod
站在顶峰看星星1 个月前
powershell 终端 执行 pnpm -v报错
vue·node·react·angular·nvm
码飞_CC1 个月前
2024 年的 Node.js 生态系统
前端·node·生态系统
G皮T2 个月前
【Elasticsearch】Elasticsearch 中的节点角色
elasticsearch·node·集群·主节点·节点·节点角色·数据节点
tekin2 个月前
vue项目源码调试方法 ,chrome调试控制台工作区使用,利用chrome控制台调试vue项目源码的方法 图解
前端·javascript·chrome·webpack·vue·node·debug
lll...lll2 个月前
智联招聘瑞数4-5特殊版
java·前端·后端·python·node·智联招聘·瑞数
HaanLen2 个月前
利用node连接mongodb实现一个小型后端服务系统demo
数据库·mongodb·http·node·file
lll...lll3 个月前
龙国南方航空滑块acw_v2+cookie+风控处理+type后缀
java·python·go·node·航空·滑块·acw_sc__v2