node.js + express + docker + mysql + jwt 实现用户管理restful api

我是傲夫靠斯,欢迎关注我的公众号【前端工程师的自我修养】,搜索f2ef2e,每天更新。

今天我们用node.js + express + docker + mysql + jwt来搞一个简单版的用户管理restful api,里面有基础的用户注册、用户登录和获取用户信息的功能。其中用到了express的路由,使用express-validator作为表单验证器,用docker运行mysql容器,密码的加密,jwt生成用户token等等。下面来搞起来

用到的技术

  • nodejs
  • express
  • mysql
  • jwt
  • docker

第一步:创建项目目录

mkdir nodejs-auth-mysql-rest-api
cd nodejs-auth-mysql-rest-api
npm init -y

安装依赖

npm install express express-validator mysql body-parser jsonwebtoken bcryptjs cors --save
  • express
    • 启动基本的http服务
  • express-validator
    • 用来验证表单是否合法
  • mysql
    • 连接mysql数据库,存储数据,查询数据
  • body-parser
    • 解析post请求体的数据
  • jsonwebtoken
    • 用于生成jwt的token
  • bcryptjs
    • 加密用户注册的密码
  • cors
    • 允许跨域的请求访问

第二步:创建数据库和表

这里我不用在电脑上去安装mysql数据库,我们使用docker的方式在本机上运行一个mysql容器,需要熟悉一些基本的docker使用。

创建数据文件夹

mkdir data

创建mysql容器

docker run -v "$PWD/data":/var/lib/mysql --name dev-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
  • docker run
    • 运行docker容器
  • -v “$PWD/data”:/var/lib/mysql
    • 将容器内的数据存储目录映射到宿主机的目录,避免容器关闭导致的数据丢失
  • –name dev-mysql
    • 容器名称
  • -p 3306:3306
    • 将容器内的3306端口映射到宿主机上,这里我是为了方便,正常是不会这样映射,因为很危险。
  • -e MYSQL_ROOT_PASSWORD=123456
    • 将root密码设置为123456
  • -d
    • 将容器在后台运行
  • mysql:5.7
    • 容器的镜像和镜像版本

查看运行容器

docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED          STATUS          PORTS                               NAMES
b1808287e831   mysql:5.7              "docker-entrypoint.s…"   15 seconds ago   Up 12 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp   dev-mysql

停止容器

docker stop b1808287e831

查看所有容器

docker ps -a
CONTAINER ID   IMAGE                  COMMAND                  CREATED          STATUS                      PORTS                    NAMES
b1808287e831   mysql:5.7              "docker-entrypoint.s…"   15 minutes ago   Exited (0) 10 seconds ago                            dev-mysql

启动容器

docker start b1808287e831

创建数据库和表

在目录中创建database.sql,用户创建数据表

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `email` varchar(50) NOT NULL,
  `password` varchar(200) NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY email (email)
 ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

执行下面命令在容器内创建数据库和表

# 将sql文件拷贝进容器内
docker cp $PWD/database.sql b1808287e831:/database.sql
# 进入容器内
docker exec -it b1808287e831 bin/bash
# 连接mysql 输入密码
mysql -u root -p
# 显示所有数据数据库
show databases;
# 创建数据库
create database `node-app`;
# 使用数据库
use `node-app`;
# 导入数据表
source /database.sql;
# 退出mysql
exit;
# 退出容器
exit;

第三步:在nodejs中连接数据库

创建dbConnection.js

const mysql = require('mysql');

const conn = mysql.createConnection({
  host: '127.0.0.1',
  user: 'root',
  password: '123456',
  database: 'node-app'
}); 
 
conn.connect(function(err) {
  if (err) throw err;
  console.log('数据库连接成功');
});

module.exports = conn;

测试是否能连接成功

node dbConnection.js
# 数据库连接成功

第四步:创建express服务

创建server.js

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const indexRouter = require('./router.js');

const app = express();

app.use(express.json());

app.use(bodyParser.json());

app.use(bodyParser.urlencoded({
    extended: true
}));

app.use(cors());

app.use('/api', indexRouter);

// 处理错误
app.use((err, req, res, next) => {
    // console.log(err);
    err.statusCode = err.statusCode || 500;
    err.message = err.message || "Internal Server Error";
    res.status(err.statusCode).json({
      message: err.message,
    });
});

app.listen(3000,() => console.log(`服务启动成功:http://localhost:3000`));

第五步:创建路由和验证器

创建validation.js文件

const { check } = require('express-validator');

exports.signupValidation = [
  check('name', '请输入用户名').not().isEmpty(),
  check('email', '请输入合法的邮箱').isEmail(),
  check('password', '密码至少是6位哦').isLength({ min: 6 })
]

exports.loginValidation = [
  check('email', '请输入合法的邮箱').isEmail(),
  check('password', '密码至少是6位哦').isLength({ min: 6 })
]

创建router.js文件

const express = require('express');
const router = express.Router();
const db = require('./dbConnection');
const { signupValidation, loginValidation } = require('./validation');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

const JWT_SECRET = 'my-secret'

router.post('/register', signupValidation, (req, res, next) => {
  db.query(
    `SELECT * FROM users WHERE LOWER(email) = LOWER(${db.escape(
      req.body.email
    )});`,
    (err, result) => {
      if (result.length) {
        return res.status(409).send({
          msg: '邮箱已被注册'
        });
      } else {
        // 如果可以注册,
        bcrypt.hash(req.body.password, 10, (err, hash) => {
          if (err) {
            return res.status(500).send({
              msg: err
            });
          } else {
            // 密码加密后,存入数据库
            db.query(
              `INSERT INTO users (name, email, password) VALUES ('${req.body.name}', ${db.escape(
                req.body.email
              )}, ${db.escape(hash)})`,
              (err, result) => {
                if (err) {
                  return res.status(400).send({
                    msg: err
                  });
                }
                return res.status(201).send({
                  msg: '用户注册成功'
                });
              }
            );
          }
        });
      }
    }
  );
});

router.post('/login', loginValidation, (req, res, next) => {
  db.query(
    `SELECT * FROM users WHERE email = ${db.escape(req.body.email)};`,
    (err, result) => {
      // 用户不存在
      if (err) {
        // throw err;
        return res.status(400).send({
          msg: err
        });
      }
      if (!result.length) {
        return res.status(401).send({
          msg: '用户名或密码错误'
        });
      }
      // 检查密码是否正确
      bcrypt.compare(
        req.body.password,
        result[0]['password'],
        (bErr, bResult) => {
          // 密码错误
          if (bErr) {
            // throw bErr;
            return res.status(401).send({
              msg: '用户名或密码错误'
            });
          }
          if (bResult) {
            const token = jwt.sign({ id: result[0].id }, JWT_SECRET, { expiresIn: '1h' });
            db.query(
              `UPDATE users SET last_login = now() WHERE id = '${result[0].id}'`
            );
            return res.status(200).send({
              msg: '登陆成功',
              token,
              user: result[0]
            });
          }
          return res.status(401).send({
            msg: '用户名或密码错误'
          });
        }
      );
    }
  );
});

router.post('/get-user', signupValidation, (req, res, next) => {
  if (
    !req.headers.authorization ||
    !req.headers.authorization.startsWith('Bearer') ||
    !req.headers.authorization.split(' ')[1]
  ) {
    return res.status(422).json({
      message: "缺少Token",
    });
  }
  const theToken = req.headers.authorization.split(' ')[1];
  const decoded = jwt.verify(theToken, JWT_SECRET);
  db.query('SELECT * FROM users where id=?', decoded.id, function (error, results, fields) {
    if (error) throw error;
    return res.send({ error: false, data: results[0], message: '请求成功' });
  });
});

module.exports = router;

第六步:运行Express服务

安装nodemon

npm install nodemon --save-dev

修改package.json

"scripts": {
    "start": "nodemon server.js"
},

运行项目

npm start
# 服务启动成功:http://localhost:3000
# 数据库连接成功

第七步:使用postman测试

注册用户

POST - http://localhost:3000/api/register

WX20210902-220458@2x

查看数据库是否有数据

WX20210902-220531@2x

登陆

POST - http://localhost:3000/api/login

WX20210902-220720@2x

获取用户信息

POST - http://localhost:3000/api/get-user

WX20210902-221044@2x

源码

Github:https://github.com/cmdfas/nodejs-auth-mysql-rest-api

欢迎关注我的公众号【前端工程师的自我修养】,搜索f2ef2e,每天更新。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值