数据加密
This commit is contained in:
parent
ffd872a113
commit
889b4327bd
|
|
@ -34,6 +34,7 @@
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persist": "^1.0.0",
|
"pinia-plugin-persist": "^1.0.0",
|
||||||
"quill": "^2.0.3",
|
"quill": "^2.0.3",
|
||||||
|
"sm-crypto": "^0.3.13",
|
||||||
"tinymce": "^7.6.0",
|
"tinymce": "^7.6.0",
|
||||||
"vite-plugin-html": "^3.2.0",
|
"vite-plugin-html": "^3.2.0",
|
||||||
"vite-plugin-zip-file": "^2.2.0",
|
"vite-plugin-zip-file": "^2.2.0",
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,11 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import NProgress from 'nprogress'
|
import NProgress from 'nprogress'
|
||||||
// import { mainStore } from 'store/main'
|
// import { mainStore } from 'store/main'
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from 'element-plus'
|
||||||
import { saveAs } from 'file-saver'
|
import { saveAs } from 'file-saver'
|
||||||
import router from "@/router"
|
import router from '@/router'
|
||||||
|
import { tansParams } from '@/utils/bonus'
|
||||||
|
import { decryptWithSM4, encryptWithSM4, hashWithSM3AndSalt } from '@/utils/sm'
|
||||||
// const store = mainStore()
|
// const store = mainStore()
|
||||||
|
|
||||||
// const CancelToken = axios.CancelToken
|
// const CancelToken = axios.CancelToken
|
||||||
|
|
@ -15,53 +17,110 @@ const VITE_token = import.meta.env.VITE_token
|
||||||
const VITE_LocalFlag = import.meta.env.VITE_LocalFlag
|
const VITE_LocalFlag = import.meta.env.VITE_LocalFlag
|
||||||
|
|
||||||
const VITE_ENV = import.meta.env.VITE_ENV
|
const VITE_ENV = import.meta.env.VITE_ENV
|
||||||
|
const iwsData: any = sessionStorage.getItem('data') || null
|
||||||
|
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: baseUrl,
|
baseURL: baseUrl,
|
||||||
timeout: 60000
|
timeout: 60000,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 请求拦截
|
||||||
service.interceptors.request.use(
|
service.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
config.headers['Authorization'] = localStorage.getItem('tokenNew')
|
config.headers['Authorization'] = localStorage.getItem('tokenNew')
|
||||||
|
// 入参是否加密
|
||||||
|
config.headers['encryptRequest'] = 'true'
|
||||||
|
// 数据完整性校验
|
||||||
|
config.headers['checkIntegrity'] = 'true'
|
||||||
|
// 回参是否加密
|
||||||
|
config.headers['encryptResponse'] = 'true'
|
||||||
|
|
||||||
|
// 对请求数据进行加密
|
||||||
|
if (config.method === 'get' && config.params) {
|
||||||
|
let url = config.url + '?' + tansParams(config.params)
|
||||||
|
url = url.slice(0, -1)
|
||||||
|
config.params = {}
|
||||||
|
config.url = url
|
||||||
|
}
|
||||||
|
if (config.data) {
|
||||||
|
let data = typeof config.data === 'object' ? JSON.stringify(config.data) : config.data
|
||||||
|
config.data = encryptWithSM4(data + '|' + hashWithSM3AndSalt(data))
|
||||||
|
}
|
||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
return error
|
return error
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
// 响应拦截
|
// 响应拦截
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
(res) => {
|
(res) => {
|
||||||
ElMessage.closeAll()
|
ElMessage.closeAll()
|
||||||
const { data } = res
|
let data: any = null
|
||||||
|
if (res.headers.encryptresponse && !res.data.hasOwnProperty('code')) {
|
||||||
|
data = JSON.parse(decryptWithSM4(res.data))
|
||||||
|
} else {
|
||||||
|
data = res.data
|
||||||
|
}
|
||||||
|
// console.log('🚀 ~ 响应-data:', data)
|
||||||
if (data.code == '200') {
|
if (data.code == '200') {
|
||||||
return data
|
return data
|
||||||
} else if (data.code == '403') {
|
} else if (data.code == '403') {
|
||||||
ElMessage.error('请重新登录')
|
ElMessage.error('请重新登录')
|
||||||
|
// 根据环境变量 VITE_API_URL 判断是否是本地开发环境
|
||||||
|
if (import.meta.env.VITE_API_URL == '/proxyApi') {
|
||||||
router.push('/login')
|
router.push('/login')
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.replace(
|
||||||
|
'http://sgwpdm.ah.sgcc.com.cn/iws/cas/login?appId=3874dcb953f184dc75450e33d6d6d4fa&service=http://sgwpdm.ah.sgcc.com.cn/iws/mall-view/',
|
||||||
|
)
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
} else if (data.code == '401') {
|
} else if (data.code == '401') {
|
||||||
ElMessage.error(data.msg)
|
ElMessage.error('请重新登录')
|
||||||
|
if (import.meta.env.VITE_API_URL == '/proxyApi') {
|
||||||
router.push('/login')
|
router.push('/login')
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.replace(
|
||||||
|
'http://sgwpdm.ah.sgcc.com.cn/iws/cas/login?appId=3874dcb953f184dc75450e33d6d6d4fa&service=http://sgwpdm.ah.sgcc.com.cn/iws/mall-view/',
|
||||||
|
)
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
} else if (data.code == '500') {
|
} else if (data.code == '500') {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: data.msg,
|
message: data.msg,
|
||||||
duration: 1000,
|
duration: 1000,
|
||||||
})
|
})
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
// ElMessage.error('请求失败')
|
// ElMessage.error('请求失败')
|
||||||
// console.log('error-异常', error)
|
// console.log('error-异常', error)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
export function get(url: string, params: any) {
|
export function get(url: string, params: any) {
|
||||||
|
// if (iwsData) {
|
||||||
|
// service
|
||||||
|
// .get(
|
||||||
|
// `http://sgwpdm.ah.sgcc.com.cn/iws/cas/api/validate/sk?sessionKey=${iwsData.sessionKey}`,
|
||||||
|
// )
|
||||||
|
// .then((res: any) => {
|
||||||
|
// console.log(res, '请求结果')
|
||||||
|
// if (res.code != 200) {
|
||||||
|
// window.location.replace(
|
||||||
|
// 'http://sgwpdm.ah.sgcc.com.cn/iws/cas/login?appId=3874dcb953f184dc75450e33d6d6d4fa&service=http://sgwpdm.ah.sgcc.com.cn/iws/mall-view/',
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return false
|
||||||
|
// })
|
||||||
|
// }
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// NProgress.start()
|
// NProgress.start()
|
||||||
service
|
service
|
||||||
|
|
@ -81,11 +140,28 @@ export function get(url: string, params: any) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export function post(url: string, params: any) {
|
export function post(url: string, params: any) {
|
||||||
|
// if (iwsData) {
|
||||||
|
// service
|
||||||
|
// .get(
|
||||||
|
// `http://sgwpdm.ah.sgcc.com.cn/iws/cas/api/validate/sk?sessionKey=${iwsData.sessionKey}`,
|
||||||
|
// )
|
||||||
|
// .then((res: any) => {
|
||||||
|
// console.log(res, '请求结果')
|
||||||
|
|
||||||
|
// if (res.code != 200) {
|
||||||
|
// window.location.replace(
|
||||||
|
// 'http://sgwpdm.ah.sgcc.com.cn/iws/cas/login?appId=3874dcb953f184dc75450e33d6d6d4fa&service=http://sgwpdm.ah.sgcc.com.cn/iws/mall-view/',
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return false
|
||||||
|
// })
|
||||||
|
// }
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// NProgress.start()
|
// NProgress.start()
|
||||||
service
|
service
|
||||||
.post(url, params, {
|
.post(url, params, {
|
||||||
headers: { 'Content-Type': 'application/json; charset=utf-8' }
|
headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
||||||
})
|
})
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
NProgress.done()
|
NProgress.done()
|
||||||
|
|
@ -112,7 +188,7 @@ export function upload(url: string, params: any) {
|
||||||
NProgress.start()
|
NProgress.start()
|
||||||
service
|
service
|
||||||
.post(url, formData, {
|
.post(url, formData, {
|
||||||
headers: { 'Content-Type': 'multipart/form-data' }
|
headers: { 'Content-Type': 'multipart/form-data' },
|
||||||
})
|
})
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
NProgress.done()
|
NProgress.done()
|
||||||
|
|
@ -130,38 +206,41 @@ export function upload(url: string, params: any) {
|
||||||
}
|
}
|
||||||
export function download(url: string, params: any, fileName: string = 'downloaded_file') {
|
export function download(url: string, params: any, fileName: string = 'downloaded_file') {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
NProgress.start(); // 开始进度条
|
NProgress.start() // 开始进度条
|
||||||
|
|
||||||
service
|
service
|
||||||
.post(url, params, {
|
.post(url, params, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
},
|
},
|
||||||
responseType: 'blob' // 请求返回数据类型为 Blob(二进制流)
|
responseType: 'blob', // 请求返回数据类型为 Blob(二进制流)
|
||||||
})
|
})
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
NProgress.done(); // 结束进度条
|
NProgress.done() // 结束进度条
|
||||||
|
|
||||||
// 判断返回的内容类型是否是 Blob
|
// 判断返回的内容类型是否是 Blob
|
||||||
const contentType = res.headers['content-type'] || '';
|
const contentType = res.headers['content-type'] || ''
|
||||||
if (!contentType.includes('application/octet-stream') && !contentType.includes('application/pdf')) {
|
if (
|
||||||
reject('文件类型不正确');
|
!contentType.includes('application/octet-stream') &&
|
||||||
return;
|
!contentType.includes('application/pdf')
|
||||||
|
) {
|
||||||
|
reject('文件类型不正确')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理文件下载
|
// 处理文件下载
|
||||||
const blob = new Blob([res.data], { type: contentType });
|
const blob = new Blob([res.data], { type: contentType })
|
||||||
|
|
||||||
// 使用 file-saver 保存文件
|
// 使用 file-saver 保存文件
|
||||||
saveAs(blob, fileName);
|
saveAs(blob, fileName)
|
||||||
|
|
||||||
resolve('文件下载成功');
|
resolve('文件下载成功')
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
NProgress.done(); // 结束进度条
|
NProgress.done() // 结束进度条
|
||||||
reject(err?.data || '下载失败');
|
reject(err?.data || '下载失败')
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function put(url: string, params: any) {
|
export function put(url: string, params: any) {
|
||||||
|
|
@ -169,7 +248,7 @@ export function put(url: string, params: any) {
|
||||||
NProgress.start()
|
NProgress.start()
|
||||||
service
|
service
|
||||||
.put(url, params, {
|
.put(url, params, {
|
||||||
headers: { 'Content-Type': 'application/json; charset=utf-8' }
|
headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
||||||
})
|
})
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
NProgress.done()
|
NProgress.done()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
* 参数处理
|
||||||
|
* @param {*} params 参数
|
||||||
|
*/
|
||||||
|
export function tansParams(params: any) {
|
||||||
|
let result = ''
|
||||||
|
for (const propName of Object.keys(params)) {
|
||||||
|
const value = params[propName]
|
||||||
|
var part = encodeURIComponent(propName) + '='
|
||||||
|
if (value !== null && value !== '' && typeof value !== 'undefined') {
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
for (const key of Object.keys(value)) {
|
||||||
|
if (value[key] !== null && value[key] !== '' && typeof value[key] !== 'undefined') {
|
||||||
|
let params = propName + '[' + key + ']'
|
||||||
|
var subPart = encodeURIComponent(params) + '='
|
||||||
|
result += subPart + encodeURIComponent(value[key]) + '&'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result += part + encodeURIComponent(value) + '&'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// SM 配置
|
||||||
|
export const SM_CONFIG = {
|
||||||
|
SALT: '2cc0c5f9f1749f1632efa9f63e902323', // SM3 盐值(16 字节)
|
||||||
|
SM4_KEY:"78d1295afa99449b99d6f83820e6965c", // SM4 对称加密密钥
|
||||||
|
SM4_SALT:"f555adf6c01d0ab0761e626a2dae34a2",
|
||||||
|
SM2_PUBLIC_KEY: 'your-public-key', // SM2 公钥
|
||||||
|
SM2_PRIVATE_KEY: 'your-private-key' // SM2 私钥
|
||||||
|
}
|
||||||
|
// AES 配置
|
||||||
|
export const AES_CONFIG = {
|
||||||
|
AES_KEY: 'zhgd@bonus@zhgd@bonus@1234567890', // AES key值
|
||||||
|
AES_IV: '1234567812345678' // AES 偏移量
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateUUID() {
|
||||||
|
// 使用当前时间戳和随机数生成一个 UUID
|
||||||
|
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||||
|
const r = Math.random() * 16 | 0; // 生成随机数
|
||||||
|
const v = c === 'x' ? r : (r & 0x3 | 0x8); // 根据 UUID 规范生成相应的值
|
||||||
|
return v.toString(16); // 转换为十六进制
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
// src/utils/encryption.js
|
||||||
|
import { sm2, sm3, sm4 } from 'sm-crypto'
|
||||||
|
// 配置项,例如盐值、SM2 公私钥、SM4 密钥
|
||||||
|
import { SM_CONFIG } from './configure'
|
||||||
|
import SM4 from 'sm-crypto/src/sm4'
|
||||||
|
import { hexToArray } from 'sm-crypto/src/sm2/utils'
|
||||||
|
|
||||||
|
// SM3 哈希
|
||||||
|
export function hashSM3(text: any) {
|
||||||
|
// 对数据进行哈希计算
|
||||||
|
return sm3(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 SM3 进行哈希并加入盐值
|
||||||
|
export function hashWithSM3AndSalt(text: any) {
|
||||||
|
// 将文本和盐值拼接在一起
|
||||||
|
const textWithSalt = SM_CONFIG.SALT + text
|
||||||
|
// 使用 SM3 进行哈希
|
||||||
|
return hashSM3(textWithSalt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SM2 加密
|
||||||
|
export function encryptWithSM2(text: any) {
|
||||||
|
// SM2 公钥加密
|
||||||
|
return sm2.doEncrypt(text, SM_CONFIG.SM2_PUBLIC_KEY)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SM2 解密
|
||||||
|
export function decryptWithSM2(encryptedText: any) {
|
||||||
|
// SM2 私钥解密
|
||||||
|
return sm2.doDecrypt(encryptedText, SM_CONFIG.SM2_PRIVATE_KEY)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 加密函数
|
||||||
|
* @param {string} plainText
|
||||||
|
* @returns {string} 加密后的密文(Hex 编码格式)
|
||||||
|
*/
|
||||||
|
export function encryptWithSM4(plainText: any) {
|
||||||
|
return sm4.encrypt(plainText, SM_CONFIG.SM4_KEY, {
|
||||||
|
mode: 'cbc',
|
||||||
|
padding: 'pkcs#5',
|
||||||
|
iv: SM_CONFIG.SM4_SALT,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密函数
|
||||||
|
* @param {string} cipherText
|
||||||
|
* @returns {string} 解密后的明文
|
||||||
|
*/
|
||||||
|
export function decryptWithSM4(cipherText: any) {
|
||||||
|
return SM4.decrypt(cipherText, SM_CONFIG.SM4_KEY, {
|
||||||
|
mode: 'cbc',
|
||||||
|
padding: 'pkcs#5',
|
||||||
|
iv: SM_CONFIG.SM4_SALT,
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue