Créez une plateforme d'achat simple à partir de zéro (1): https://blog.csdn.net/time_____/article/details/105191286
Code source du projet (mise à jour continue): https://gitee.com/DieHunter/myCode/ L'
article précédent sur tree / master / shopping a terminé la construction du corps principal du projet et du module d'extension. Le but de cet article est de créer la fonction de vérification des jetons et de connexion côté serveur.
Serveur:
Structure des répertoires de fichiers
Le fichier d'entrée est server.js , configurez-le simplement, laissez-le courir
const express = require("express");
const app = express();
app.listen(1024, () => {
console.log("Server Start~");
});
Utilisez le terminal pour accéder au répertoire server.js, entrez le nœud serveur pour exécuter le fichier d'entrée et affichez Server Start ~ pour indiquer que l'opération a réussi, puis introduisez certains 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~");
});
Une fois tous les paramètres terminés, passez à l'étape suivante pour configurer le routage et la vérification des jetons
Créez une nouvelle classe statique dans le fichier utils.js et introduisez jwt (jsonwebtoken), créez une nouvelle classe statique de configuration dans le fichier config.js pour stocker les variables de configuration (nom de l'interface, clé publique, constante), et devez également l'utiliser Crypto effectue le cryptage et le décryptage des données, le cryptage du sel de mot de passe Bcrypt
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);
}
}
Après avoir configuré les utils, configurez le routage, créez un nouveau fichier routes.js sous le dossier routes et utilisez le jeton pour vérifier que l'utilisateur est 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
});
});
}
};
Configurer 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",//用户登录
}
}
Par la suite, créez une nouvelle interface de routage de gestion des utilisateurs , mais avant cela, nous devons configurer la base de données
- Téléchargez Robo3t et installez
- Créer une nouvelle base de données, le nom de ma nouvelle base de données ici est Shopping
- Créer une nouvelle table de base de données, ici je crée une table d'utilisateurs
Connectez-vous à la base de données
- Créer une nouvelle connexion à la base de données dans model.js (mode observateur principal, similaire à la surveillance des événements personnalisés par socket)
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 } }
-
Le nouveau schéma de base de données est utilisé pour se connecter à la table de données , ici nous dépouillons directement les éléments de configuration dans le fichier config.js
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 } }
-
Nouvelle configuration de champ par défaut de la table utilisateur dans 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 } } } },
Ce qui précède est le code back-end pour la configuration, la vérification des jetons et la connexion
Pour résumer
Il est nécessaire d'intégrer le projet dans une idée de conception similaire à MVC La séparation du modèle de données et de la couche de contrôle peut rendre le code clair, réutilisable et maintenable.