实现的场景:
登录接口,登录完成后服务器会返回加密的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();
//高阶函数 解决无法使用promise
const { 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存放token
res.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');7
text += 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;
};
完整代码存放与阿里云盘的语雀文件夹中