数据加密与问题修复
This commit is contained in:
parent
d1e35d9352
commit
08c3874947
|
|
@ -28,6 +28,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",
|
||||||
|
|
@ -4456,6 +4457,19 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sm-crypto": {
|
||||||
|
"version": "0.3.13",
|
||||||
|
"resolved": "https://registry.npmmirror.com/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
||||||
|
"integrity": "sha512-ztNF+pZq6viCPMA1A6KKu3bgpkmYti5avykRHbcFIdSipFdkVmfUw2CnpM2kBJyppIalqvczLNM3wR8OQ0pT5w==",
|
||||||
|
"dependencies": {
|
||||||
|
"jsbn": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sm-crypto/node_modules/jsbn": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/jsbn/-/jsbn-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
|
||||||
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://repo.huaweicloud.com/repository/npm/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://repo.huaweicloud.com/repository/npm/source-map/-/source-map-0.6.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,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",
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import NProgress from 'nprogress'
|
||||||
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
|
||||||
|
|
@ -22,9 +24,28 @@ const service = axios.create({
|
||||||
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) => {
|
||||||
|
|
@ -35,7 +56,9 @@ service.interceptors.request.use(
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
(res) => {
|
(res) => {
|
||||||
ElMessage.closeAll()
|
ElMessage.closeAll()
|
||||||
const { data } = res
|
// const { data } = res
|
||||||
|
const data = JSON.parse(decryptWithSM4(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') {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ const activeLoginCompanyName = ref('')
|
||||||
const searchCheckVisible = ref(false)
|
const searchCheckVisible = ref(false)
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
const { userInfo, token }: any = storeToRefs(store)
|
const { userInfo, token }: any = storeToRefs(store)
|
||||||
|
const tokenNew = localStorage.getItem('tokenNew')
|
||||||
if (roles?.length > 0) {
|
if (roles?.length > 0) {
|
||||||
isAdmin.value = roles.some((e: any) => e.roleKey == 'admin')
|
isAdmin.value = roles.some((e: any) => e.roleKey == 'admin')
|
||||||
}
|
}
|
||||||
|
|
@ -52,12 +53,13 @@ watch(userInfo, (newValue, oldCount) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
watch(token, (newValue, oldCount) => {
|
// watch(token, (newValue, oldCount) => {
|
||||||
if (newValue) {
|
// if (newValue) {
|
||||||
getUserListData()
|
// getUserListData()
|
||||||
getBookCarDetailsData()
|
// getBookCarDetailsData()
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
// 监听 tokenNew 有值时请求用户信息
|
||||||
|
|
||||||
const setActiveCompanyName = () => {
|
const setActiveCompanyName = () => {
|
||||||
// const companyList = userStore.companyList
|
// const companyList = userStore.companyList
|
||||||
|
|
@ -244,10 +246,14 @@ const onSelectRoles = (type: number) => {
|
||||||
|
|
||||||
const getBookCarDetailsData = async () => {
|
const getBookCarDetailsData = async () => {
|
||||||
const res: any = await getBookCarDetailsApi()
|
const res: any = await getBookCarDetailsApi()
|
||||||
|
console.log('🚀 ~ getBookCarDetailsData ~ res:', res)
|
||||||
let amountNum = 0
|
let amountNum = 0
|
||||||
res.data.forEach((e: any) => {
|
if (res.data && res.data.length > 0) {
|
||||||
amountNum = e.devInfoVoList.length + amountNum
|
res.data.forEach((e: any) => {
|
||||||
})
|
amountNum = e.devInfoVoList.length + amountNum
|
||||||
|
console.log('🚀 ~ res.data.forEach ~ amountNum:', amountNum)
|
||||||
|
})
|
||||||
|
}
|
||||||
cart.SET_CART_NUM(amountNum)
|
cart.SET_CART_NUM(amountNum)
|
||||||
}
|
}
|
||||||
const cartNum = computed(() => {
|
const cartNum = computed(() => {
|
||||||
|
|
@ -372,9 +378,12 @@ const resetPhone = async () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// onMounted(() => {
|
onMounted(() => {
|
||||||
// circleUrl.value = store.userInfo.avatar
|
if (tokenNew) {
|
||||||
// })
|
getUserListData()
|
||||||
|
getBookCarDetailsData()
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -36,12 +36,12 @@ const allList = [
|
||||||
{ title: '租赁订单', name: 'orderManagement', permission: ['2'] },
|
{ title: '租赁订单', name: 'orderManagement', permission: ['2'] },
|
||||||
{ title: '收货地址管理', name: 'address-manage', permission: ['2'] },
|
{ title: '收货地址管理', name: 'address-manage', permission: ['2'] },
|
||||||
{ title: '合同管理', name: 'contract-manage', permission: ['1'] },
|
{ title: '合同管理', name: 'contract-manage', permission: ['1'] },
|
||||||
{ title: '快捷消息设置', name: 'quickMessage', permission: ['1'] },
|
// { title: '快捷消息设置', name: 'quickMessage', permission: ['1'] },
|
||||||
// { title: '个人中心', name: 'personalCenter', permission: ['1'] },
|
// { title: '个人中心', name: 'personalCenter', permission: ['1'] },
|
||||||
// { title: '个人中心', name: 'personalCenter', permission: ['2'] },
|
// { title: '个人中心', name: 'personalCenter', permission: ['2'] },
|
||||||
]
|
]
|
||||||
|
|
||||||
const rolesType = ref('承租方')
|
const rolesType = ref(localStorage.getItem('rolesTypeName') || '出租方')
|
||||||
const menuList: any = computed(() => {
|
const menuList: any = computed(() => {
|
||||||
if (rolesType.value == '承租方') return allList.filter((e) => e.permission.includes('2'))
|
if (rolesType.value == '承租方') return allList.filter((e) => e.permission.includes('2'))
|
||||||
if (rolesType.value == '出租方') return allList.filter((e) => e.permission.includes('1'))
|
if (rolesType.value == '出租方') return allList.filter((e) => e.permission.includes('1'))
|
||||||
|
|
@ -65,11 +65,13 @@ const onChange = (val: any) => {
|
||||||
router.push({
|
router.push({
|
||||||
name: 'sourcingNeed',
|
name: 'sourcingNeed',
|
||||||
})
|
})
|
||||||
|
localStorage.setItem('rolesTypeName', '承租方')
|
||||||
} else {
|
} else {
|
||||||
store.editcurrentMenuItem('goodsManagement')
|
store.editcurrentMenuItem('goodsManagement')
|
||||||
router.push({
|
router.push({
|
||||||
name: 'goodsManagement',
|
name: 'goodsManagement',
|
||||||
})
|
})
|
||||||
|
localStorage.setItem('rolesTypeName', '出租方')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
|
@ -101,7 +103,7 @@ onBeforeUnmount(() => {
|
||||||
<el-menu
|
<el-menu
|
||||||
class="el-menu-vertical-demo"
|
class="el-menu-vertical-demo"
|
||||||
@select="handleSelect"
|
@select="handleSelect"
|
||||||
:default-active="route.name"
|
:default-active="route && route.name ? route.name : ''"
|
||||||
>
|
>
|
||||||
<template v-for="(item, index) in menuList" :key="index">
|
<template v-for="(item, index) in menuList" :key="index">
|
||||||
<el-menu-item :index="item.name">
|
<el-menu-item :index="item.name">
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,8 @@ const statusList: any = [
|
||||||
]
|
]
|
||||||
|
|
||||||
const orderText = (status: any) => {
|
const orderText = (status: any) => {
|
||||||
return statusList.filter((e: any) => e.id == status)[0].name
|
const statusItem = statusList.find((e: any) => e.id == status)
|
||||||
|
return statusItem ? statusItem.name : ''
|
||||||
}
|
}
|
||||||
const orderType = (status: any) => {
|
const orderType = (status: any) => {
|
||||||
if (status == 1 || status == 2 || status == 3 || status == 5) return 'primary'
|
if (status == 1 || status == 2 || status == 3 || status == 5) return 'primary'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue