vue3.2实现AES加密解密,秘钥通过API获取,并混淆秘钥,后端thinkphp

aes.ts文件

javascript 复制代码
import CryptoJS from "crypto-js";
import axios from "axios";

export const encrypt = async(data: any) => {
  let storeKey = sessionStorage.getItem('a')
  let storeIv:any = sessionStorage.getItem('i')
  // 如果秘钥或 IV 不存在,尝试获取秘钥
  if (!storeKey || !storeIv) {
    await fetchSecretKey(); // 确保秘钥已被获取
    storeKey = sessionStorage.getItem('a'); // 再次获取秘钥
    storeIv = sessionStorage.getItem('i'); // 再次获取 IV
  }

  if (!storeKey || !storeIv) {
    throw new Error("秘钥或 IV 不存在.");
  }
  let secretKey = storeKey.replace('FiedGSe5fg6', '').replace('F//Eset5fGDet', '')
  let key = CryptoJS.enc.Base64.parse(secretKey);
  let replaceIv = storeIv.replace('DGers', '').replace('HrdReK', '')
  let iv = CryptoJS.enc.Utf8.parse(replaceIv)
  let srcs = CryptoJS.enc.Utf8.parse(JSON.stringify(data));

  let encrypted = CryptoJS.AES.encrypt(srcs, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
  });

  return encrypted.toString();
};

export const decrypt = async(cipherText: any) => {
  let storeKey = sessionStorage.getItem('a')
  let storeIv:any = sessionStorage.getItem('i')
  // 如果秘钥或 IV 不存在,尝试获取秘钥
  if (!storeKey || !storeIv) {
    await fetchSecretKey(); // 确保秘钥已被获取
    storeKey = sessionStorage.getItem('a'); // 再次获取秘钥
    storeIv = sessionStorage.getItem('i'); // 再次获取 IV
  }

  if (!storeKey || !storeIv) {
    throw new Error("秘钥或 IV 不存在.");
  }
  let secretKey = storeKey.replace('FiedGSe5fg6', '').replace('F//Eset5fGDet', '')
  let key = CryptoJS.enc.Base64.parse(secretKey);
  let replaceIv = storeIv.replace('DGers', '').replace('HrdReK', '')
  let iv = CryptoJS.enc.Utf8.parse(replaceIv)
  const decrypted = CryptoJS.AES.decrypt(cipherText, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
  });

  return decrypted.toString(CryptoJS.enc.Utf8);
};


// 获取秘钥并存储在会话缓存中
export const fetchSecretKey = async () => {
  // 检查会话缓存中是否已经有秘钥
  const cachedKey = sessionStorage.getItem('a');
  
  if (cachedKey) {
    return;
  }

  try {
    // 获取当前时间戳
    const timestamp = Date.now();
    const nonce = generateNonce(); // 生成随机 nonce

    // 临时使用一个默认的签名密钥,可以替换为你后端使用的密钥
    const tempSecret = 'defaultSecretKey';
    const signature = generateSignature(tempSecret, timestamp, nonce); // 生成签名

    // 发送请求获取秘钥,带上签名
    const response = await axios.post('/api_getKey', {
      timestamp,
      nonce,
      signature,
    });
    const rawKey = response.data.aesKey;
    // 存储到会话缓存中
    sessionStorage.setItem('a', rawKey);
    sessionStorage.setItem('i', response.data.iv);

  } catch (error) {
    console.error('Error fetching secret key:', error);
  }
};

// 初始化函数,只有第一次项目打开时才执行获取秘钥的逻辑
export const initializeSecretKey = async () => {
  const secretKey = sessionStorage.getItem('a')
  if (!secretKey) {
    await fetchSecretKey(); // 调用获取秘钥的函数
  }
};

// 生成随机字符串作为 nonce
const generateNonce = (): string => {
  return Math.random().toString(36).substr(2, 15);
};

// 生成签名
const generateSignature = (secretKey: string, timestamp: number, nonce: string): string => {
  const message = `${secretKey}${timestamp}${nonce}`;
  return CryptoJS.SHA256(message).toString();
};

后端

php 复制代码
// 获取加密密钥的 API 接口
    public function getKey()
    {
        // 获取请求参数
        $timestamp = Request::post('timestamp');
        $nonce = Request::post('nonce');
        $signature = Request::post('signature');

        // 验证签名
        if (!$this->verifySignature($timestamp, $nonce, $signature)) {
            return json(['error' => '无效签名或请求已过期'], 403);
        }

        // 签名验证通过后,返回密钥(或其他敏感信息)
        // AES密钥 
        $secretKey = '秘钥';
        // 1Ww;w(czeHDyFN@T   DGers  HrdReK
        $iv = '向量'; 
        return json(['aesKey' => $secretKey,'iv' => $iv]);
    }

    // 签名验证
    private function verifySignature($timestamp, $nonce, $signature)
    {
        // 检查时间戳是否在合理范围内(例如5分钟内)
        $now = time() * 1000; // 转换为毫秒
        if (abs($now - $timestamp) > 5 * 60 * 1000) {
            return false; // 请求超时
        }

        // 重新生成签名
        $dataToSign = 'defaultSecretKey' . $timestamp . $nonce;
        $serverSignature = hash('sha256', $dataToSign);

        // 比较客户端的签名与服务器生成的签名是否一致
        if ($serverSignature !== $signature) {
            return false; // 签名不匹配
        }

        // 如果签名正确,返回 true
        return true;
    }
相关推荐
用户30745969820719 分钟前
容器(Container)—— 对象的“智能工厂+调度官”
后端·thinkphp
李慕婉学姐2 小时前
【开题答辩过程】以《基于微信小程序垃圾分类图像识别技术实现》为例,不会开题答辩的可以进来看看
spring boot·微信小程序·vue
故事不长丨18 小时前
【Java SpringBoot+Vue 实现视频文件上传与存储】
java·javascript·spring boot·vscode·后端·vue·intellij-idea
咚咚咚小柒1 天前
【前端】Webpack相关(长期更新)
前端·javascript·webpack·前端框架·node.js·vue·scss
老华带你飞2 天前
房屋租赁|房屋出租|房屋租赁系统|基于Springboot的房屋租赁系统设计与实现(源码+数据库+文档)
java·数据库·spring boot·vue·论文·毕设·房屋租赁系统
前端摸鱼匠2 天前
Vue 3 事件修饰符全解析:从 .stop 到 .passive,彻底掌握前端交互的艺术
前端·vue.js·node.js·vue·交互
Crazy Struggle2 天前
.NET 8.0 + Vue 企业级在线培训系统(开源、免费、支持多种主流数据库)
vue·.net 8.0·后台管理系统
韩立学长3 天前
【开题答辩实录分享】以《植物病虫害在线答疑小程序的设计与实现》为例进行答辩实录分享
spring boot·小程序·vue
whltaoin4 天前
【JAVA全栈项目】弧图图-智能图床 SpringBoot+Vue3 :[框架开荒:一文全步骤打通前后端项目全流程]
java·spring boot·vue·开源项目·全栈·cos
清灵xmf5 天前
Vue + TSX 中使用 class 报错 解决方法
vue