From e40f0ebab8d4d075d251fb8bbe2689f054f7c456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=AF=E8=BE=89?= Date: Thu, 30 Apr 2026 13:28:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=8A=A0=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/globalFunction.js | 14 ++++++++ config.js | 13 ++++++-- utils/crypto.js | 37 +++++++++++++++++++++ utils/request.js | 71 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 utils/crypto.js diff --git a/common/globalFunction.js b/common/globalFunction.js index de59a3b..901de40 100644 --- a/common/globalFunction.js +++ b/common/globalFunction.js @@ -1,4 +1,6 @@ import useUserStore from "../stores/useUserStore"; +import { sm4Encrypt, sm4Decrypt } from '@/utils/crypto'; + import { request, createRequest, @@ -384,6 +386,14 @@ const formatTotal = (total) => { return `${roundedTotal}+`; }; +export function sm2_Decrypt(word, key) { + return SM.decrypt(word, key); +} + +export function sm2_Encrypt(word, key) { + return SM.encrypt(word, key); +} + export function formatDate(isoString) { const date = new Date(isoString); const year = date.getFullYear(); @@ -1041,4 +1051,8 @@ export default { insertSortData, isInWechatMiniProgramWebview, isEmptyObject, + sm4Decrypt, + sm4Encrypt, + sm2_Decrypt, + sm2_Encrypt, } diff --git a/config.js b/config.js index 43388d2..dff82d2 100644 --- a/config.js +++ b/config.js @@ -6,8 +6,8 @@ */ export default { // baseUrl: 'http://39.98.44.136:8080', // 测试 - baseUrl: 'https://www.xjksly.cn/api/ks', // 正式环境 - // baseUrl: 'http://ks.zhaopinzao8dian.com/api/ks', // 测试 + // baseUrl: 'https://www.xjksly.cn/api/ks', // 正式环境 + baseUrl: 'http://ks.zhaopinzao8dian.com/api/ks', // 测试 // LCBaseUrl:'http://10.110.145.145:9100',//内网端口 // LCBaseUrlInner:'http://10.110.145.145:10100',//招聘、培训、帮扶 @@ -88,5 +88,12 @@ export default { title: '找工作,用 AI 更高效|青岛市智能求职平台', desc: '融合海量岗位、智能简历匹配、竞争力分析,助你精准锁定理想职位!', imgUrl: 'https://qd.zhaopinzao8dian.com/file/csn/qd_shareLogo.jpg', - } + }, + // SM4 加密配置 + sm4Config: { + key: '86C63180C1306ABC4D8F989E0A0BC9F3', + mode: 'ECB', + iv: 'UISwD9fW6cFh9SNS', + cipherType: 'base64', + }, } diff --git a/utils/crypto.js b/utils/crypto.js new file mode 100644 index 0000000..bef188e --- /dev/null +++ b/utils/crypto.js @@ -0,0 +1,37 @@ +import { sm4 } from 'sm-crypto'; + +export function sm4Decrypt(key, value, mode = "hex") { + try { + if (key.length !== 32) { + uni.showToast({ title: '密钥必须是32位16进制字符串(128位)', icon: 'none' }); + return; + } + const decrypted = sm4.decrypt(value, key, { + mode: 'ecb', + cipherType: mode === 'hex' ? 'hex' : 'base64', + padding: 'pkcs#5' + }); + return decrypted; + } catch (e) { + console.error('sm4 decrypt error:', e); + return value; + } +} + +export function sm4Encrypt(key, value, mode = "hex") { + try { + if (key.length !== 32) { + uni.showToast({ title: '密钥必须是32位16进制字符串(128位)', icon: 'none' }); + return; + } + const encrypted = sm4.encrypt(value, key, { + mode: 'ecb', + cipherType: mode === 'hex' ? 'hex' : 'base64', + padding: 'pkcs#5' + }); + return encrypted; + } catch (e) { + console.error('sm4 encrypt error:', e); + return value; + } +} diff --git a/utils/request.js b/utils/request.js index 648f0fc..d63981a 100644 --- a/utils/request.js +++ b/utils/request.js @@ -1,5 +1,66 @@ import config from "@/config.js" +import { sm4Encrypt, sm4Decrypt } from '@/utils/crypto'; import useUserStore from '@/stores/useUserStore'; + +const needToEncryptSet = new Set([ + 'POST:/app/login', + 'GET:/app/user/resume', + 'POST:/app/user/resume', + 'POST:/app/user/experience/edit', + 'POST:/app/user/experience/delete', + 'GET:/app/user/experience/getSingle', + 'GET:/app/user/experience/list', + 'POST:/app/user/cert', + 'POST:/app/user/getUserArchives', +]); + +const encryptPathPrefixes = [ + '/app/common/', + '/app/chat/', + '/app/speech/', + '/app/job/', + '/app/company/', +]; + +const isEncryptNeeded = (method, url) => { + const key = `${method.toUpperCase()}:${url}`; + if (needToEncryptSet.has(key)) return true; + for (const encryptKey of needToEncryptSet) { + const [encryptMethod, encryptUrl] = encryptKey.split(':'); + if (encryptMethod === method.toUpperCase() && url.startsWith(encryptUrl.split('/{')[0])) { + return true; + } + } + for (const prefix of encryptPathPrefixes) { + if (url.startsWith(prefix)) { + return true; + } + } + return false; +}; + +const encryptRequestData = (data) => { + const jsonData = JSON.stringify(data); + // const jsonData = JSON.stringify({a: '1'}); + console.log('[请求] 加密前:', jsonData) + return { + encrypted: true, + encryptedData: sm4Encrypt(config.sm4Config.key, jsonData), + timestamp: Date.now(), + }; +}; + +const handleResponseData = (resData) => { + try { + if (resData?.encrypted) { + const decrypted = sm4Decrypt(config.sm4Config.key, resData.encryptedData); + resData = JSON.parse(decrypted); + } + } catch (e) { + console.error('[请求] 解密失败:', e.message); + } + return resData; +}; export function request({ url, method = 'GET', @@ -89,25 +150,27 @@ export function createRequest(url, data = {}, method = 'GET', loading = false, h if(needHeader){ header["Authorization"] = encodeURIComponent(Authorization); } + const requestData = isEncryptNeeded(method, url) ? encryptRequestData(data) : data; return new Promise((resolve, reject) => { uni.request({ url: config.baseUrl + url, method: method, - data: data, + data: requestData, header, success: resData => { // 响应拦截 if (resData.statusCode === 200) { + const responseData = handleResponseData(resData.data) const { code, msg - } = resData.data + } = responseData if (code === 200) { - resolve(resData.data) + resolve(responseData) return } // 处理业务错误 - if (resData.data?.code === 401 || resData.data?.code === 402) { + if (responseData?.code === 401 || responseData?.code === 402) { useUserStore().logOut() } // 显示具体的错误信息