Build a simple shopping platform from scratch (2)

Build a simple shopping platform from scratch (1): https://blog.csdn.net/time_____/article/details/105191286
Project source code (continuous update):
https://gitee.com/DieHunter/myCode/ The

previous article on tree/master/shopping completed the construction of the main body of the project and the plug-in module. The purpose of this article is to build the server-side token verification and login function

Server:

File directory structure

The entry file is server.js , simply configure it, let him run

const express = require("express");
const app = express();

app.listen(1024, () => {
  console.log("Server Start~");
});

Use the terminal to cd to the server.js directory, enter the node server to run the entry file, and display Server Start~ to indicate successful operation, and then introduce some modules

const express = require("express");
const app = express();
const routes = require("./routes/routes");
const cors = require("cors"); //引入cors模块(解决跨域问题)
const path = require("path");
app.use(cors());
app.all("*", function (req, res, next) {
  //设置允许跨域的域名,*代表允许任意域名跨域
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "content-type"); //允许的header类型
  res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS"); //跨域允许的请求方式
  next(); //是否继续向下执行
});
let bodyParser = require("body-parser"); //post传输数据类型
app.use(
  bodyParser.urlencoded({
    extended: false,
  })
);
new routes(app);//初始化路由
app.use(bodyParser.json());
app.use("/public", express.static(path.join(__dirname, "./public")));//静态目录

app.listen(1024, () => {
  console.log("Server Start~");
});

After all settings are completed, proceed to the next step to configure routing and token verification

Create a new static class in the utils.js file, and introduce jwt (jsonwebtoken), create a new config static class in the config.js file to store configuration variables (interface name, public key, constant), and also need to use it Crypto performs data encryption and decryption, Bcrypt password salt encryption

utils.js

const jwt = require("jsonwebtoken");
const config = require("../config/config");
const cryptoJS = require("crypto-js");//用来加密解密前端参数
let { UserKey, AdminKey,CryptoKey} = config;//token加密关键字,秘钥
let key = cryptoJS.enc.Utf8.parse(CryptoKey);//生成16进制秘钥
module.exports = class Utils {
   static parseUrl(req, res) {//获取前端传递的参数
    return req.method == "POST" ? req.body : this.urlSplit(req.url);
  }
   static urlSplit(url) {//get获取的参数解析
    let list = url.split("?")[1].split("&");
    let leng = list.length;
    let obj = {};
    for (let i = 0; i < leng; i++) {
      let key = list[i].split("=")[0];
      let val = list[i].split("=")[1];
      obj[key] = val;
    }
    return obj;
  }
/*
   * @param {string} type 'user'||'admin'      用户类型
   * @param {string} user                      用户名  
   * @param {bool} rempsd                      是否记住密码
   */
  static createToken = (type, user, rempsd) => {//生成token,用户登录时调用
    let payload = {
      user: user,
    };
    return jwt.sign(payload, type == "admin" ? AdminKey : UserKey, {
      expiresIn: rempsd ? "3d" : "6h",
    });
  };
 /*
   * @param {object} req       前端请求对象
   * @param {object} res       服务端接收对象
   * @param {fn} next          中间件响应方法
   */
  static checkToken = (req, res, next) => {
    let _data = this.parseUrl(req, res); //解析前端参数
    if (_data.crypto) {
      _data = this.getCrypto(_data.crypto); //对前端参数解密
    }
    let isUser = true; //用户
    let isAdmin = true; //管理员
    let _decoded = ""; //加密的用户名
    jwt.verify(_data.token, UserKey, function (err, decoded) {
      if (err) {
        isUser = false;
      } else {
        _decoded = decoded;
      }
    });
    jwt.verify(_data.token, AdminKey, function (err, decoded) {
      if (err) {
        isAdmin = false;
      } else {
        _decoded = decoded;
      }
    });
    if (isUser || isAdmin) {
      _data.id = _decoded;
      _data.userTokenType = isAdmin ? "admin" : "user";
      res._data = _data;
      next(); //中间件响应
    } else {
      res.send({
        result: -999,
        msg: "登录超时,请重新登录",
      });
    }
  };
/* Crypto加密方法
   * @param {object} _data       对用户请求后端的参数进行加密
   */
  static setCrypto(_data) {
    let encrypted = cryptoJS.AES.encrypt(JSON.stringify(_data), key, {
      mode: cryptoJS.mode.ECB,
      padding: cryptoJS.pad.Pkcs7,
    });
    return encrypted.toString();
  }
 /* Crypto解密方法
   * @param {string} _token       将秘文解密成对象形式
   */
  static getCrypto(_token) {
    _token = decodeURIComponent(_token); //前端传参有特殊字符(中文)时转义(替换百分号)
    let decrypt = cryptoJS.AES.decrypt(_token, key, {
      mode: cryptoJS.mode.ECB,
      padding: cryptoJS.pad.Pkcs7,
    });
    return JSON.parse(cryptoJS.enc.Utf8.stringify(decrypt).toString());
  }
  static createBcrypt(password) {//加密密码
    return bcrypt.hashSync(password, bcrypt.genSaltSync(10));
  }
  static checkBcrypt(_password, _hash) {//对比密码
    return bcrypt.compareSync(_password, _hash);
  }
}

After configuring the utils, configure the routing, create a new routes.js file under the routes folder, and use the token to verify that the user is correct

const Util = require("../utils/utils");
const Config = require("../config/config");
module.exports = class Route {
  constructor(app) {
    app.get(Config.ServerApi.checkToken, Util.checkToken, (req, res) => {
      res.send({
        result: 1,
        msg: "验证成功",
        data: res._data
      });
    });
  }
};

Configure config.js

module.exports = {
  Agreement: "http://",//协议
  DataBaseUrl: "127.0.0.1",//ip或域名
  DataBasePort: ":27017",//数据库端口
  DataBaseName: "shopping",//数据库文档名称
  ServerUrl: "",
  ServerPort: ":1024",//服务端请求端口
  Path: "/",//路由名
  UserKey: "user",//用户token加密标识
  AdminKey: "admin",//管理员token加密标识
  CryptoKey: "tokenkey",//Crypto加密关键字,用于生成16进制秘钥
  ServerApi: {//接口名称
    checkToken: "/checkToken",//token验证
    userLogin: "/userLogin",//用户登录
  }
}

Subsequently, create a new user management routing interface , but before that, we need to configure the database

  1. Download Robo3t and install
  2. Create a new database, here my new database name is Shopping
  3. Create a new database table, here I am creating a users table

Connect to the database

  1. Create a new database connection in model.js (principle observer mode, similar to socket monitoring custom events)
    const mongoose = require('mongoose');
    const config = require('../../config/config')
    module.exports = class Mongoose {
        constructor() {
            mongoose.connect(`mongodb://${config.DataBaseUrl+config.DataBasePort+config.Path+config.DataBaseName}`, {
                useNewUrlParser: true
            });
            this.db = mongoose.connection;
            this.db.on("error", function (error) {
                console.log("Err:" + error);
            });
    
            this.db.on("open", function () {
                console.log("Connet Success~");
            });
    
            this.db.on('disconnected', function () {
                console.log('Connet Stop~');
            });
            return mongoose
        }
    }

     

  2. The new database schema is used to connect to the data table , here we directly strip the configuration items to the config.js file

    const _mongoose = require('./model');
    let mongoose = new _mongoose()
    const _schema = mongoose.Schema;
    module.exports = class Schema {
        constructor(config) {
            let schema = new _schema(config.data);
            let Model = mongoose.model(config.modelName, schema); //新建数据库
            return Model
        }
    }

     

  3. New user table default field configuration in config.js

    Collections: {
        Users: {
          modelName: "users",
          data: {
            headPic: {//头像
              type: String,
              required: false,
              default: "public/assets/img/default.gif"
            },
            userType: {//用户类型(管理员/用户)
              type: String,
              required: true,
            },
            username: {//用户名
              type: String,
              required: true,
            },
            password: {//密码
              type: String,
              required: true
            },
            sex: {//性别
              type: String,
              required: true
            },
            mailaddress: {//邮箱地址
              type: String,
              required: true
            },
            mailurl: {//邮箱类型
              type: String,
              required: true
            },
            alladdress: {//省市县
              type: Array,
              required: false,
              default: []
            },
            address: {//具体地址
              type: String,
              required: false,
              default: ''
            },
            descript: {//个人说明
              type: String,
              required: false,
              default: ''
            },
            time: {//注册时间
              type: String,
              required: true
            },
            isactive: {//是否冻结用户
              type: Boolean,
              default: true
            }
          }
        }
      },

     

The above is the back-end code for configuration, token verification and login 

to sum up

It is necessary to build the project into a design idea similar to MVC. The separation of the data model and the control layer can make the code clear, reusability and maintainability.

Guess you like

Origin blog.csdn.net/time_____/article/details/105408640