express登录流程

整体流程

  1. 客户端使用账号和密码登录
  2. 服务端使用账号查询用户是否存在,如果不存在则返回错误信息
  3. 服务端把传过来的密码进行加密,然后和数据库加密后的密码进行比对,正确则生成token返回客户端
  4. 客户端收到token存储在localStorage中
  5. 在客户端请求拦截器中对请求头进行操作,使每次请求带上token
  6. 服务端每次请求时解析传过来的token进行登录状态验证,失败则通知客户端跳转登录页面

user表结构

CREATE TABLE `user` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `account` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '账号',
  `password` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '密码',
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '用户名',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `status` tinyint DEFAULT '0' COMMENT '状态:0 正常,1 关闭',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `memo` text COMMENT '备注',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8mb3 COMMENT='报表管理系统用户表'
;

密码加密

安装crypto-js插件

npm i crypto-js

创建encryption.js导出encrypt和decrypt进行加密和解密
创建用户时对密码进行加密处理存入数据库,登录时对传入密码进行加密然后和数据库密码进行比对。

encryption.js

// 密码加密解密
const CryptoJS = require("crypto-js");
// 十六位十六进制数作为密钥
const SECRET_KEY = CryptoJS.enc.Utf8.parse("IhahaKVXpw7ZSt2l");
// 十六位十六进制数作为密钥偏移量
const SECRET_IV = CryptoJS.enc.Utf8.parse("IhahaKVXpw7ZSt2l");
/**
 * 加密
 */
function encrypt(data) {
  if (typeof data === "object") {
    try {
      // eslint-disable-next-line no-param-reassign
      data = JSON.stringify(data);
    } catch (error) {
      console.log("encrypt error:", error);
    }
  }
  const dataHex = CryptoJS.enc.Utf8.parse(data);
  const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
    iv: SECRET_IV,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
  });
  return encrypted.ciphertext.toString();
}

/**
 * 解密
 */
function decrypt(word) {
  const encryptedHexStr = CryptoJS.enc.Hex.parse(data);
  const str = CryptoJS.enc.Base64.stringify(encryptedHexStr);
  const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
    iv: SECRET_IV,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
  });
  const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
  return decryptedStr.toString();
}

module.exports = {
  encrypt,
  decrypt,
};


了解token

此次生成token的方案为JSON Web Tokens,JWT是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。
JWT的结构由 Header:头部;Payload:负载;Signature:签名; 三部分组成,用句号(.)分割。一个JWT就像这样 AAAAA.BBBBBB.CCCCCC。

  • Header:包含两部分,一部分是类型,另一部分是算法就想这样{“alg”:“HS256”,“typ”:“JWT”},最后用Base64Url 编码JW生成JWT的第一部分。
  • Payload:JWT的第二部分包含Claims,Claims就是包含一个实体和其他数据信息,有三种类型:registered, public和private claims。Payload就想这样:{“sub”:“1234567890”,“name”:“JohnDoe”,“admin”:true},最后对Payload进行Base64Url 编码JW生成JWT的第二部分。
  • Signature:用Header定义的算法对编码后的Header,Payload和secret进行签名,签名的目的就是防止被篡改。

token的生成

首先安装依赖 jsonwebtoken 和 express-jwt ,jsonwebtoken用于token的生成, express-jwt用于在express框架下进行token校验。

npm i jsonwebtoken express-jwt

建立token.js

const jwt = require("jsonwebtoken");
const secret = "this_token"; //自定义密匙

// 生成token
let createToken = function (data) {
  let token = jwt.sign(data, secret, {
    expiresIn: 60 * 60 * 24 * 3, // 以s作为单位(目前设置的过期时间为3天)
  });
  return token;
};
//验证token
const verToken = function (token) {
  let info = jwt.verify(token, secret, (error, decoded) => {
    if (error) {
      // token过期或者无效
      return { tokenOut: true };
    }
  });
  return info;
};
module.exports = { secret, createToken, verToken };

createToken用法示例

const token = createToken({
  name: info.name,
  userid: info.id,
  access: info.access,
});
// token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoi5biFIiwidXNlcmlkIjoxLCJhY2Nlc3MiOiJhZG1pbiIsImlhdCI6MTY1Mjc3NjQyNywiZXhwIjoxNjUzMDM1NjI3fQ.6KFhZ_BEZlDtDn4_l7McKrb3Qw2PtV1ZqDFQ11U-0S4

token的验证

expressjwt会在路由请求时解析token,此处要求前端token传入请求头的Authorization中,格式为:

options.headers['Authorization'] = `Bearer ${localStorage.getItem('token') || ''}`;

在app.js中进行token的校验与错误处理

// 引入依赖
const { expressjwt } = require("express-jwt");

/** ---  代码前部  ---  */
// 使用中间件解析token,unless用于排除无需校验的路由(比如: 登录)
app.use(
  expressjwt({
    secret,
    algorithms: ["HS256"], // 使用何种加密算法解析
  }).unless({ path: ["/api/account"] }) // 登录页无需校验
);

/** ---  代码后部,推荐写在express错误处理前面  ---  */
// 捕获express-jwt 解析 Token错误
function errorHandler(err, req, res, next) {
  console.log(err, err.name);
  let code = 500;
  let message = "Internal Server Error";
  // token解析的错误
  if (err.name === "UnauthorizedError") {
    code = 401;
    message = "no login";
  }
  res.statusCode = code;
  res.send({
    status: code,
    message,
  });
}
app.use(errorHandler);
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值