Sfoglia il codice sorgente

数据加密处理

lrf 10 mesi fa
parent
commit
5f88fd1667
7 ha cambiato i file con 6703 aggiunte e 34 eliminazioni
  1. 3 1
      .env.development
  2. 2 1
      .env.production
  3. 6582 18
      package-lock.json
  4. 3 1
      package.json
  5. 1 2
      src/layout/parts/Sidebar.vue
  6. 47 11
      src/utils/axios-wrapper.js
  7. 65 0
      src/utils/crypto.js

+ 3 - 1
.env.development

@@ -1,6 +1,8 @@
 ## 开发环境
 NODE_ENV='development'
-
+# 是否启用加密,应与服务配合使用,否则会一端加密,一端不解密
+# VITE必须得写,不写就需要改默认配置.没必要
+VITE_USE_CRYPTO = true
 # 应用端口
 VITE_APP_PORT = 3000
 

+ 2 - 1
.env.production

@@ -3,7 +3,8 @@ NODE_ENV='production'
 
 # 应用端口
 VITE_APP_PORT = 3000
-
+# 是否启用加密,应与服务配合使用,否则会一端加密,一端不解密
+VITE_USE_CRYPTO = true
 # 代理前缀
 VITE_APP_BASE_API = '/ts/frame/api'
 

File diff suppressed because it is too large
+ 6582 - 18
package-lock.json


+ 3 - 1
package.json

@@ -13,11 +13,13 @@
   "dependencies": {
     "@element-plus/icons-vue": "^2.3.1",
     "@vueuse/core": "^10.7.2",
+    "@vueuse/integrations": "^10.9.0",
     "@wangeditor/editor": "^5.1.23",
     "@wangeditor/editor-for-vue": "5.1.10",
-    "@vueuse/integrations": "^10.9.0",
     "axios": "^1.6.7",
+    "crypto-js": "^4.2.0",
     "element-plus": "^2.5.6",
+    "jsencrypt": "^3.3.2",
     "lodash-es": "^4.17.21",
     "moment": "^2.30.1",
     "nprogress": "^0.2.0",

+ 1 - 2
src/layout/parts/Sidebar.vue

@@ -4,7 +4,7 @@
     <el-row class="sidebar">
       <el-col :span="24" class="main">
         <el-col :span="24" class="first">
-          <img :src="siteInfo.logo_url" class="logo-image" />
+          <img src="/logo.png" class="logo-image" />
           <span class="logo-title">{{ $t('login.title') }}</span>
         </el-col>
         <el-col :span="24" class="second">
@@ -18,7 +18,6 @@
 </template>
 
 <script setup>
-import { siteInfo } from '@/layout/site'
 import { UserStore } from '@/store/user'
 import menuItem from './sidebar/items.vue'
 import { useRoute } from 'vue-router'

+ 47 - 11
src/utils/axios-wrapper.js

@@ -1,16 +1,18 @@
 /* eslint-disable no-console */
 /* eslint-disable no-param-reassign */
 
-import { get, isObject } from 'lodash-es'
+import { get, isObject, pick } from 'lodash-es'
 import Axios from 'axios'
 import { trimData, isNullOrUndefined } from './util-methods'
 import { ErrorCode } from './error-code'
 import router from '@/router'
 import i18n from '@/lang'
+import * as crypto from './crypto'
 let currentRequests = 0
+const { VITE_APP_BASE_API, VITE_USE_CRYPTO } = import.meta.env
 
 export class AxiosWrapper {
-  constructor({ baseUrl = import.meta.env.VITE_APP_BASE_API, unwrap = true } = {}) {
+  constructor({ baseUrl = VITE_APP_BASE_API, unwrap = true } = {}) {
     this.baseUrl = baseUrl
     this.unwrap = unwrap
   }
@@ -71,28 +73,62 @@ export class AxiosWrapper {
     const params = get(options, 'params')
     const url = AxiosWrapper.merge(uri, params)
     currentRequests += 1
-    // Indicator.open({
-    //   spinnerType: 'fading-circle',
-    // });
     try {
       let returnData
       const axios = Axios.create({
         baseURL: this.baseUrl,
         withCredentials: true
       })
-      // if (util.token && util.token !== null) axios.defaults.headers.common.Authorization = util.token;
+      // #region 加密部分
+      // 加密,需要根据env文件判断是否启用加密
+      if (VITE_USE_CRYPTO) {
+        // 生成随机字符串
+        const reqCode = crypto.getRandomString()
+        axios.interceptors.request.use(async (config) => {
+          // 加密真实使用的加密字符串
+          const deReqCode = crypto.pemEncrypt(reqCode)
+          // 加密数据并替换
+          config.transformRequest = (data) => {
+            if (data) {
+              // 加密 加密字符串
+              const strData = JSON.stringify(data)
+              // 加密数据
+              const enCodeData = crypto.encrypt(deReqCode, strData)
+              // 替换数据位置
+              return { data: enCodeData }
+            }
+            return undefined
+          }
+          // 添加请求头,将 加密的真实使用加密字符串附上
+          config.headers['api-token'] = deReqCode
+          return config
+        })
+        axios.interceptors.response.use(
+          (response) => {
+            if (get(response, 'data.data')) {
+              let data = crypto.decrypt(reqCode, get(response, 'data.data'))
+              const dobj = JSON.parse(data || '{}')
+              const others = pick(get(response, 'data'), ['errcode', 'errmsg'])
+              response.data = { ...others, ...dobj }
+            }
+            return response
+          },
+          (error) => Promise.reject(error)
+        )
+      }
+      // #endregion
       const token = localStorage.getItem('token')
-      const apiToken = localStorage.getItem('apiToken')
       if (token) axios.defaults.headers.common['token'] = token
-      if (apiToken) axios.defaults.headers.common['api-token'] = apiToken
-      const res = await axios.request({
+
+      const requestOptions = {
         method: isNullOrUndefined(data) ? 'get' : 'post',
         url,
         data,
         responseType: 'json',
         ...options
-      })
-      const returnRes = res.data
+      }
+      const res = await axios.request(requestOptions)
+      let returnRes = res.data
       const { errcode, errmsg, details } = returnRes
       if (errcode) {
         console.warn(`[${uri}] fail: ${errcode}-${errmsg} ${details}`)

+ 65 - 0
src/utils/crypto.js

@@ -0,0 +1,65 @@
+import JSEncrypt from 'jsencrypt'
+import CryptoJS from 'crypto-js'
+/**
+ * 请求参数加密
+ * @param {string} code 加密字符串
+ * @param {string} data 加密数据
+ */
+export function encrypt(code, data) {
+  const ivStr = code.substring(0, 16)
+  const key = CryptoJS.enc.Utf8.parse(code)
+  const iv = CryptoJS.enc.Utf8.parse(ivStr)
+  const srcs = CryptoJS.enc.Utf8.parse(data)
+  const encrypted = CryptoJS.AES.encrypt(srcs, key, {
+    iv,
+    mode: CryptoJS.mode.CBC,
+    padding: CryptoJS.pad.Pkcs7
+  })
+  return encrypted.toString()
+}
+/**
+ * 解密参数加密
+ * @param {string} code 加密字符串
+ * @param {string} data 解密数据
+ */
+export function decrypt(code, data) {
+  const ivStr = code.substring(0, 16)
+  const key = CryptoJS.enc.Utf8.parse(code)
+  const iv = CryptoJS.enc.Utf8.parse(ivStr)
+  const decrypt = CryptoJS.AES.decrypt(data, key, {
+    iv,
+    mode: CryptoJS.mode.CBC,
+    padding: CryptoJS.pad.Pkcs7
+  })
+  return decrypt.toString(CryptoJS.enc.Utf8)
+}
+/**
+ * RSA非对称加密
+ * @param {string} code 加密内容
+ * @returns {string} decodeStr加密后的内容
+ */
+export function pemEncrypt(code) {
+  const jse = new JSEncrypt()
+  const publicKey = `-----BEGIN PUBLIC KEY-----
+  MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKPquvtF8xW2gkjoOb4e4IFryeL1GuW+
+  PyZi4AnKNU0WnYdNmNDeI74mVh8xj+lI7OW5wEsgfdqXbWT51uuWgf0CAwEAAQ==
+  -----END PUBLIC KEY-----`
+  jse.setPublicKey(publicKey)
+  const data = jse.encrypt(code)
+  if (data) return data
+  return ''
+}
+/**
+ * 生成随机字符串
+ * @param {number} len 需要的长度
+ * @returns {string} 随机字符串
+ */
+export function getRandomString(len = 32) {
+  let result = ''
+  const inOptions = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789'
+  for (let i = 0; i < len; i += 1) {
+    result += inOptions.charAt(Math.floor(Math.random() * inOptions.length))
+  }
+
+  return result
+}