欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

[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)
            })
        },