实现的场景:
登录接口,登录完成后服务器会返回加密的token,token存放在cookie中,由于有些设别无法使用cookie需要将token放在响应头的authorization中
添加学生接口:请求中必须携带cookie,服务端会解析cookie的token,由于设备中有差别,解析请求头的authorization中的token,都这两个地方都没有时,说明该用户没有权限访问该接口
实现所需要的技术点
url中的路径匹配:使用的插件path-to-regexp
token的加密与解密:使用node模块中的crypto模块
cookie的管理:使用的插件cookie-parser
代码
用户发送登录请求时,服务器生成token将其加密,存于cookie中
const adminService = require('../../services/adminService');const express = require('express');// 路由const router = express.Router();//高阶函数 解决无法使用promiseconst { asyncHandler } = require('../getSendResult');// 加密与解密const cryptoToken = require('../../util/cryptoToken')router.post('/login', asyncHandler( async(req,res,next) => {const result = await adminService.login(req.body.loginId, req.body.loginPwd);if (result) {// 加密const id = cryptoToken.encrypt(result.id);res.cookie('token', id, {path: '/',domain: 'localhost',});// 当为手机端是无法使用cookie的// 需要在响应头的authorization存放tokenres.header('authorization', id);res.header('Access-Control-Allow-Origin', '*');}return result;}))module.exports = router;
路由匹配,那些路由需要有token才能访问
/*** 那些接口需要有cookie才能访问*/const needTokenApi = [{ method: 'POST', path: '/api/student' },{ method: 'PUT', path: '/api/student/:id' },{ method: 'GET', path: '/api/student' },];const { getErr } = require('./getSendResult');// 将路径转化为正则进行匹配const { pathToRegexp, match, parse, compile } = require('path-to-regexp');const cryptoToken = require('../util/cryptoToken');module.exports = (req, res, next) => {const apis = needTokenApi.filter((ele) => {const reg = pathToRegexp(ele.path);return ele.method == req.method && reg.test(req.path);});if (apis.length === 0) {next();return;}/*** 是否有token*/let token = req.cookies.token;if (!token) {token = req.headers.authorization;}if (!token) {console.log('没有token');handleNonToken(req, res, next);return;}/*** token 解密*/const userId = cryptoToken.decipheriv(token);req.userId = userId;next();};/*** 没有token* @param {*} req* @param {*} res* @param {*} next*/function handleNonToken(req, res, next) {res.status(403).send(getErr('you dont have any token to access the api', 403));}
token的加密与解密
const crypto = require('crypto');// 原始密钥const key = Buffer.from('mm7h3ck87ugk9l4a');// 初始向量 初始向量必须是随机的const randomText = Math.random().toString(16).slice(-8) + Math.random().toString(16).slice(-8);// const randomText = '1bdf94c826a35d69';const iv = Buffer.from(randomText);/*** 加密* @param {*} str* @returns*/exports.encrypt = function (str) {const cry = crypto.createCipheriv('aes-128-cbc', key, iv);let text = cry.update(str.toString(), 'utf-8', 'hex');7text += cry.final('hex');return text;};/*** 解密* @param {*} token*/exports.decipheriv = function(str) {const dec = crypto.createDecipheriv('aes-128-cbc', key, iv);let text = dec.update(str.toString(), 'hex', 'utf-8');text += dec.final('utf-8');return text;};
完整代码存放与阿里云盘的语雀文件夹中
