[Spring Cloud] (5) 网关前端和后端公钥和私钥以及身份验证信息 - 前端
最编程
2024-05-01 11:40:21
...
引入jsencrypt
npm install jsencrypt --save
工具类
securityUtils.js
修改securityUtils.js增加加解密,公私钥生成的逻辑。
import crypto from "crypto";
import {JSEncrypt} from "jsencrypt";
const CryptoJS = require('crypto-js');
/** 全局变量配置-start **/
// url白名单设置
const whiteList = [
"/tick/auth/login",
"/k",
"/cn",
]
/** 全局变量配置-end **/
export default {
/**
* 读取信息
*/
get(key) {
return sessionStorage.getItem(key)
},
/**
* 添加信息
*/
set(key, value) {
sessionStorage.setItem(key, value)
},
/**
* 登录之后进行处理
*/
loginDeal(token){
this.set("token", token)
},
//************************************网关通信-start
// 与后台网关建立连接,需要请求 “/k” 接口, 拿到后端的公钥,存储。
// 再请求 “/cn” 接口,保存与后端建立通信所需要的请求。
/**
* 用于网关请求 “/k” 请求后的处理
*
* @returns {{ck: (string|null), k: string}}
*/
dealValidationMessage(data) {
this.set("publicKey", data)
},
/**
* gateway网关验证信息处理(请求头)
*/
gatewayRequest(request) {
let key = true;
whiteList.find(function (value) {
if (value === request.url) {
key = false;
}
});
// 对非白名单请求进行处理
if (key) {
// 请求体数据
let token = this.get("token")
// 请求中增加token
if (token) {
request.headers.Authorization = token;
}
}
return request;
},
/**
* 用于网关请求 “/cn” 请求前的处理
*
* @returns {{ck: (string|null), k: string}}
*/
secureConnectionPrepare() {
const publicKey = this.get("publicKey")
const publicKeyMd5 = this.strToMd5(publicKey)
let clientPublicKey = this.communication()
clientPublicKey = this.rsaEncrypt(clientPublicKey, publicKey)
return {
"k": publicKeyMd5,
"ck": clientPublicKey,
};
},
/**
* 用于网关请求 “/cn” 请求后的处理
*/
secureConnection(data) {
const privateKey = this.get("privateKey")
data = this.rsaDecrypt(data, privateKey)
data = JSON.parse(data)
this.set("secretKey", data.secretKey)
this.set("sessionId", data.sessionId)
this.set("serverPublicKey", data.publicKey)
},
//************************************网关通信-end
/**
* 生成公钥私钥对保存本地,并返回公钥
*
* @returns {string}
*/
communication() {
const keys = this.rsaGenerateKey();
const publicKey = keys.publicKey;
const privateKey = keys.privateKey;
this.set("privateKey", privateKey)
return publicKey
},
//************************************公用加密方法-start
/**
* 将字符串取值MD5
*
* @param string 字符串对象
* @returns {string} 字符串md5数值
*/
strToMd5(string) {
// 规定使用哈希算法中的MD5算法
const hash = crypto.createHash('md5');
// 可任意多次调用update(),效果相当于多个字符串相加
hash.update(string);
// hash.digest('hex')表示输出的格式为16进制
return hash.digest('hex');
},
//************************************公用加密方法-end
//************************************AES对称加解密-start
/**
* AES对称加密数据
*
* @param {String} data 待加密的数据
* @param {String} base64Key base64格式的密钥
* @returns {String} 加密后的数据
*/
encryptAES(data, base64Key) {
let encryptedBytes = null;
if (data != null && base64Key != null) {
const key = CryptoJS.enc.Base64.parse(base64Key);
encryptedBytes = CryptoJS.AES.encrypt(data, key, {mode: CryptoJS.mode.ECB});
encryptedBytes = encryptedBytes.toString();
}
return encryptedBytes;
},
/**
* AES对称-解密数据
*
* @param {String} data 待解密的数据
* @param {String} base64Key base64格式的密钥
* @returns {String} 解密后的数据
*/
decryptAES(data, base64Key) {
let decryptData = null;
if (data != null && base64Key != null) {
const key = CryptoJS.enc.Base64.parse(base64Key)
const decryptBytes = CryptoJS.AES.decrypt(data, key, {mode: CryptoJS.mode.ECB})
decryptData = CryptoJS.enc.Utf8.stringify(decryptBytes);
}
return decryptData
},
//************************************AES对称加解密-end
//************************************RSA非对称加解密-start
/**
* 非对称加解密-生成公钥与私钥
*/
rsaGenerateKey() {
let keys = {
"publicKey": "",
"privateKey": "",
}
// 创建 JSEncrypt 实例
const encrypt = new JSEncrypt();
// 生成密钥对(公钥和私钥)
const keyPair = encrypt.getKey();
// 获取公钥和私钥
keys.publicKey = keyPair.getPublicBaseKeyB64();
keys.privateKey = keyPair.getPrivateBaseKeyB64();
return keys
},
/**
* 非对称加解密-公钥认证信息(分段加密)
*
* @param string 内容
* @param publicKey 非对称私钥
* @returns {string | null}
*/
rsaEncrypt(string, publicKey) {
let encryptData = null;
if (string != null && publicKey != null) {
const encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKey);
// 根据公钥的长度确定块大小,一般为公钥长度减去一些填充长度
const blockSize = 117;
const textLength = string.length;
let encryptedBlocks = [];
// 拆分长文本为块并逐个加密
for (let i = 0; i < textLength; i += blockSize) {
const block = string.substr(i, blockSize);
const encryptedBlock = encryptor.encrypt(block);
encryptedBlocks.push(encryptedBlock);
}
// 将加密的块合并为单个字符串
encryptData = encryptedBlocks.join('');
}
return encryptData;
},
/**
* 非对称加解密-私钥解密信息(分段解密)
*
* @param string 加密内容
* @param privateKey 非对称私钥
* @returns {string | null}
*/
rsaDecrypt(string, privateKey) {
let decryptData = null;
if (string != null && privateKey != null) {
const encryptor = new JSEncrypt();
encryptor.setPrivateKey(privateKey);
// 根据私钥的长度确定块大小,一般为私钥长度减去一些填充长度
const blockSize = 172;
const encryptedLength = string.length;
let decryptedBlocks = [];
// 拆分加密文本为块并逐个解密
for (let i = 0; i < encryptedLength; i += blockSize) {
const block = string.substr(i, blockSize);
const decryptedBlock = encryptor.decrypt(block);
decryptedBlocks.push(decryptedBlock);
}
decryptData = decryptedBlocks.join('')
}
// 将解密的块合并为单个字符串
return decryptData;
},
//************************************RSA非对称加解密-end
}
请求类
增加两个请求,用于访问后端的公钥数据与其他加密数据。
系统通信密钥接口
/** 系统通信密钥 **/
getPublicKey(obj) {
return dataInterface("/k","get", obj)
},
/** 系统通信密钥 **/
cn(obj) {
return dataInterface("/cn","get", obj)
},
登录接口增加认证数据接口
此时我们希望在登陆前,获取到与后端通信的公钥私钥以及其他的认证数据。
/**
* 获取与后端建立通信的必备信息
*/
async loginApi() {
await this.connection()
await this.$http.login(this.login).then(res => {
let code = res.code
let msg = res.msg
let data = res.data
securityUtils.loginDeal(data.token)
this.token = securityUtils.get("token")
if (code === 200) {
this.$message({message: msg, duration: 1.5, description: ''})
} else {
this.$message({message: "错误", duration: 1.5, description: ''})
}
})
},
/** 与后端建立联系 **/
async connection() {
// 获取后端RSA加密公钥
await this.$http.getPublicKey().then(res => {
let data = res.data
securityUtils.dealValidationMessage(data)
});
// 获取与后端建立通信的必备信息
let data = securityUtils.secureConnectionPrepare()
await this.$http.cn(data).then(res => {
let data = res.data
securityUtils.secureConnection(data)
})
},