提交 22e56e27 authored 作者: 王鹏飞's avatar 王鹏飞

chore: 三级等保加密

上级 a79fe6fa
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
"react-redux": "^8.1.3", "react-redux": "^8.1.3",
"react-router-dom": "^6.23.1", "react-router-dom": "^6.23.1",
"redux-persist": "^6.0.0", "redux-persist": "^6.0.0",
"sm4js": "^0.0.6",
"snabbdom": "^3.6.2", "snabbdom": "^3.6.2",
"xml-formatter": "^3.6.2", "xml-formatter": "^3.6.2",
"zustand": "^4.5.5" "zustand": "^4.5.5"
...@@ -2463,8 +2464,7 @@ ...@@ -2463,8 +2464,7 @@
"type": "consulting", "type": "consulting",
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
], ]
"peer": true
}, },
"node_modules/before-after-hook": { "node_modules/before-after-hook": {
"version": "2.2.3", "version": "2.2.3",
...@@ -8312,6 +8312,15 @@ ...@@ -8312,6 +8312,15 @@
"slate": ">=0.65.3" "slate": ">=0.65.3"
} }
}, },
"node_modules/sm4js": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/sm4js/-/sm4js-0.0.6.tgz",
"integrity": "sha512-lKJWSaSksB4MbVpYXfb0cFRgTAjEAAZSxoMZ498BuGtwVQ5aB/23wJVxFLRIZQx9cyoVihK98FiOYH7VxIZyMg==",
"license": "MIT",
"dependencies": {
"base64-js": "^1.3.1"
}
},
"node_modules/snabbdom": { "node_modules/snabbdom": {
"version": "3.6.2", "version": "3.6.2",
"resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.6.2.tgz", "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.6.2.tgz",
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
"react-redux": "^8.1.3", "react-redux": "^8.1.3",
"react-router-dom": "^6.23.1", "react-router-dom": "^6.23.1",
"redux-persist": "^6.0.0", "redux-persist": "^6.0.0",
"sm4js": "^0.0.6",
"snabbdom": "^3.6.2", "snabbdom": "^3.6.2",
"xml-formatter": "^3.6.2", "xml-formatter": "^3.6.2",
"zustand": "^4.5.5" "zustand": "^4.5.5"
......
...@@ -2,6 +2,14 @@ import axios from 'axios' ...@@ -2,6 +2,14 @@ import axios from 'axios'
import md5 from 'js-md5' import md5 from 'js-md5'
import qs from 'qs' import qs from 'qs'
import { Modal, notification } from 'antd' import { Modal, notification } from 'antd'
import Sm4js from 'sm4js'
const sm4 = new Sm4js({
key: 'XDXDXU_ZIJING_01',
mode: 'cbc',
iv: 'IVIVIV_ZHIXUE_01',
cipherType: 'base64'
})
function getToken() { function getToken() {
return window.localStorage.getItem('kiwi.token') ? window.localStorage.getItem('kiwi.token') : '' return window.localStorage.getItem('kiwi.token') ? window.localStorage.getItem('kiwi.token') : ''
...@@ -23,6 +31,7 @@ function alphabeticalSort(a, b) { ...@@ -23,6 +31,7 @@ function alphabeticalSort(a, b) {
} }
const httpRequest = axios.create({ const httpRequest = axios.create({
// baseURL: import.meta.env.VITE_API_BASE_API_PREFFIX,
// timeout: 60000, // timeout: 60000,
withCredentials: true withCredentials: true
}) })
...@@ -59,6 +68,11 @@ httpRequest.interceptors.request.use( ...@@ -59,6 +68,11 @@ httpRequest.interceptors.request.use(
} }
config.headers = { ...config.headers, ...defaultHeaders } config.headers = { ...config.headers, ...defaultHeaders }
if (config.data && config.headers['Content-Type'] !== 'multipart/form-data' && import.meta.env.PROD) {
// console.log({ ...config.data, expire: timestamp + 60 })
config.data = { data: sm4.encrypt(JSON.stringify({ ...config.data, expire: timestamp + 60 })) }
}
return config return config
}, },
error => { error => {
......
/* eslint-disable */ /* eslint-disable */
import Axios from 'axios'; import Axios from 'axios'
import { message, Modal, notification } from 'antd'; import { message, Modal, notification } from 'antd'
import md5 from 'js-md5'; import md5 from 'js-md5'
import { get } from 'lodash-es'; import { get } from 'lodash-es'
import { sortObjASCII } from '@/utils/common.js'; import { sortObjASCII } from '@/utils/common.js'
import qs from 'qs'; import qs from 'qs'
import Sm4js from 'sm4js'
let errorNotified = false; // 添加全局变量
let pending = []; // 存储每个ajax请求的取消函数和ajax标识 const sm4 = new Sm4js({
let CancelToken = Axios.CancelToken; key: 'XDXDXU_ZIJING_01',
mode: 'cbc',
iv: 'IVIVIV_ZHIXUE_01',
cipherType: 'base64'
})
let pending = [] // 存储每个ajax请求的取消函数和ajax标识
let CancelToken = Axios.CancelToken
// 取消请求 方法 // 取消请求 方法
// 取消请求 方法 // 取消请求 方法
let cancelPending = (config) => { let cancelPending = config => {
pending.forEach((item) => { pending.forEach(item => {
item.cancel(); // 取消请求 item.cancel() // 取消请求
}); })
pending = []; // 清空数组 pending = [] // 清空数组
}; }
// Axios.defaults.withCredentials = true; // 默认为false 表示跨域请求时是否需要使用凭证 // Axios.defaults.withCredentials = true; // 默认为false 表示跨域请求时是否需要使用凭证
const axios = Axios.create({ const axios = Axios.create({
baseURL: import.meta.env.VITE_API_BASE_API_PREFFIX, baseURL: import.meta.env.VITE_API_BASE_API_PREFFIX,
timeout: 999999, timeout: 999999
}); })
function getToken() { function getToken() {
return window.localStorage.getItem('kiwi.token') ? window.localStorage.getItem('kiwi.token') : ''; return window.localStorage.getItem('kiwi.token') ? window.localStorage.getItem('kiwi.token') : ''
} }
// 请求拦截器 // 请求拦截器
axios.interceptors.request.use( axios.interceptors.request.use(
(config) => { config => {
// 登录流程控制中,根据本地是否存在token判断用户的登录情况 // 登录流程控制中,根据本地是否存在token判断用户的登录情况
// 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token // 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token
// 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码 // 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码
// 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。 // 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。
if (axios.errorNotified) { if (axios.errorNotified) {
return new Error(''); return new Error('')
} }
const token = getToken(); const token = getToken()
token && (config.headers.Authorization = token); // 请求头带上token token && (config.headers.Authorization = token) // 请求头带上token
// 用户编码 // 用户编码
config.headers.UserNo = window.localStorage.getItem('user_no'); config.headers.UserNo = window.localStorage.getItem('user_no')
// 应用设置 // 应用设置
const appId = 'TzEU5jPk2tu80266'; const appId = 'TzEU5jPk2tu80266'
const appSecret = '0a006048a4480481b18fef1405120b83'; const appSecret = '0a006048a4480481b18fef1405120b83'
config.headers.AppId = appId; config.headers.AppId = appId
config.headers.AppSecret = appSecret; config.headers.AppSecret = appSecret
// 签名 // 签名
var signData = qs.parse(config.data); var signData = qs.parse(config.data)
var timeStr = Date.parse(new Date()) / 1000; var timeStr = Date.parse(new Date()) / 1000
signData.appId = appId; signData.appId = appId
signData.appSecret = appSecret; signData.appSecret = appSecret
signData.timestamp = timeStr; signData.timestamp = timeStr
let s = ''; let s = ''
if (config.url.indexOf('.tiangong.cn') > -1) { if (config.url.indexOf('.tiangong.cn') > -1) {
s = config.url; s = config.url
} else { } else {
s = import.meta.env.VITE_API_URL_WORD + config.url; s = import.meta.env.VITE_API_URL_WORD + config.url
s = s.replace('/api', ''); s = s.replace('/api', '')
} }
signData.url = decodeURIComponent(s); signData.url = decodeURIComponent(s)
// signData.url = 'http: //zijing.com/index.php/user/user/getList' // signData.url = 'http: //zijing.com/index.php/user/user/getList'
signData.token = token; signData.token = token
// 按照ASCII码进行排序' // 按照ASCII码进行排序'
var dataSign = sortObjASCII(signData); var dataSign = sortObjASCII(signData)
// 转换为字符串 // 转换为字符串
var signStr = ''; var signStr = ''
for (var key in dataSign) { for (var key in dataSign) {
var str = ''; var str = ''
if (typeof signData[key] !== 'string' && signData[key].constructor !== String) { if (typeof signData[key] !== 'string' && signData[key].constructor !== String) {
str = JSON.stringify(signData[key]); str = JSON.stringify(signData[key])
} else { } else {
str = signData[key]; str = signData[key]
} }
if (signStr === '') { if (signStr === '') {
signStr = key + '=' + str; signStr = key + '=' + str
} else { } else {
signStr += '&' + key + '=' + str; signStr += '&' + key + '=' + str
} }
} }
const salt = '&4F6g4Y6b5L4R9'; const salt = '&4F6g4Y6b5L4R9'
const sign = signStr + salt; const sign = signStr + salt
config.headers.Sign = md5(md5(sign)); // 加密盐 config.headers.Sign = md5(md5(sign)) // 加密盐
config.headers.Timestamp = timeStr; // 请求时间 config.headers.Timestamp = timeStr // 请求时间
// 设置后端的语言 // 设置后端的语言
config.headers['Accept-Language'] = window.sessionStorage.getItem('lang'); config.headers['Accept-Language'] = window.sessionStorage.getItem('lang')
// config.headers['Cookie'] = 'SESSION-ID=9ec8565699e1b961561362f710674549' // config.headers['Cookie'] = 'SESSION-ID=9ec8565699e1b961561362f710674549'
// 判断当前请求是否设置了不显示Loading // 判断当前请求是否设置了不显示Loading
/* if (config.headers.showLoading !== false) { /* if (config.headers.showLoading !== false) {
...@@ -98,101 +105,107 @@ axios.interceptors.request.use( ...@@ -98,101 +105,107 @@ axios.interceptors.request.use(
} */ } */
// 在请求拦截器中,为每个请求创建一个取消令牌,并将其添加到pending数组 // 在请求拦截器中,为每个请求创建一个取消令牌,并将其添加到pending数组
config.cancelToken = new CancelToken((cancel) => { config.cancelToken = new CancelToken(cancel => {
pending.push({ url: config.url, cancel }); pending.push({ url: config.url, cancel })
}); })
return config;
}, if (config.data && config.headers['Content-Type'] !== 'multipart/form-data' && import.meta.env.PROD) {
(error) => { // console.log({ ...qs.parse(config.data), expire: timeStr + 60 })
Promise.reject(error); config.data = { data: sm4.encrypt(JSON.stringify({ ...qs.parse(config.data), expire: timeStr + 60 })) }
}
return config
}, },
); error => {
Promise.reject(error)
}
)
// 响应拦截器 // 响应拦截器
axios.interceptors.response.use( axios.interceptors.response.use(
(response = {}) => { (response = {}) => {
let code = get(response, 'data.code', ''); let code = get(response, 'data.code', '')
let msg = get(response, 'data.message', '') || get(response, 'data.msg', ''); let msg = get(response, 'data.message', '') || get(response, 'data.msg', '')
// 代表request header中没有带token // 代表request header中没有带token
let pathname = window.location.pathname; let pathname = window.location.pathname
if (code === 401 || code === 403) { if (code === 401 || code === 403) {
if (!axios.errorNotified) { if (!axios.errorNotified) {
axios.errorNotified = true; // 添加标志,表示通知已经弹出 axios.errorNotified = true // 添加标志,表示通知已经弹出
if (pathname === '/login') { if (pathname === '/login') {
return; return
} }
Modal.warning({ Modal.warning({
title: '登录状态已过期,请重新登录', title: '登录状态已过期,请重新登录',
// content: '请重新登录', // content: '请重新登录',
onOk() { onOk() {
localStorage.removeItem('kiwi.gpt.token'); localStorage.removeItem('kiwi.gpt.token')
window.location.pathname = '/login'; window.location.pathname = '/login'
}, }
}); })
cancelPending(response.config); // 取消后续请求 cancelPending(response.config) // 取消后续请求
return Promise.reject(response); return Promise.reject(response)
} }
} }
return response; return response
}, },
(error) => { error => {
const { response = {}, config = {} } = error; const { response = {}, config = {} } = error
console.error('我要的response', response, error); console.error('我要的response', response, error)
const status = get(response, 'status', 0); const status = get(response, 'status', 0)
const urlPath = get(config, 'url', 0); const urlPath = get(config, 'url', 0)
switch (status) { switch (status) {
case 401: case 401:
cancelPending(response.config); // 取消后续请求 cancelPending(response.config) // 取消后续请求
if (!axios.errorNotified) { if (!axios.errorNotified) {
axios.errorNotified = true; // 添加标志,表示通知已经弹出 axios.errorNotified = true // 添加标志,表示通知已经弹出
Modal.warning({ Modal.warning({
title: 'token过期', title: 'token过期',
content: '请重新登录', content: '请重新登录',
onOk() { onOk() {
localStorage.removeItem('kiwi.gpt.token'); localStorage.removeItem('kiwi.gpt.token')
window.location.href = '/login'; window.location.href = '/login'
}, }
}); })
} }
break; break
case 403: case 403:
cancelPending(response.config); // 取消后续请求 cancelPending(response.config) // 取消后续请求
if (!axios.errorNotified) { if (!axios.errorNotified) {
axios.errorNotified = true; // 添加标志,表示通知已经弹出 axios.errorNotified = true // 添加标志,表示通知已经弹出
Modal.warning({ Modal.warning({
title: '身份校验已过期', title: '身份校验已过期',
content: '请重新登录', content: '请重新登录',
onOk() { onOk() {
localStorage.removeItem('kiwi.gpt.token'); localStorage.removeItem('kiwi.gpt.token')
window.location.href = '/login'; window.location.href = '/login'
}, }
}); })
} }
break; break
case 404: case 404:
notification.error({ notification.error({
message: 'Error: 404 Not Found', message: 'Error: 404 Not Found',
description: `url: ${urlPath}, The requested URL was not found on the server.`, description: `url: ${urlPath}, The requested URL was not found on the server.`
}); })
break; break
case 500: case 500:
notification.error({ notification.error({
message: 'Error: 500', message: 'Error: 500',
description: `url: ${urlPath}`, description: `url: ${urlPath}`
}); })
break; break
default: default:
if (status) { if (status) {
notification.error({ notification.error({
message: `Error: ${status}`, message: `Error: ${status}`,
description: `url: ${urlPath}`, description: `url: ${urlPath}`
}); })
} }
} }
// return error; // return error;
return Promise.reject(error); return Promise.reject(error)
}, }
); )
export default axios; export default axios
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论