接口加密

This commit is contained in:
冯辉
2026-04-30 13:28:49 +08:00
parent 5007c3ca4e
commit e40f0ebab8
4 changed files with 128 additions and 7 deletions

View File

@@ -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,
}

View File

@@ -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',
},
}

37
utils/crypto.js Normal file
View File

@@ -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;
}
}

View File

@@ -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()
}
// 显示具体的错误信息