프로젝트 시나리오:
데이터가 크롤링되는 것을 방지하려면 프런트엔드와 백엔드에서 전달 및 수신되는 매개변수를 AES 암호화를 사용하여 암호화해야 합니다. 주로 CryptoJS 라이브러리의 함수 메소드인 암호화: CryptoJS.AES.encrypt(), 복호화: CryptoJS.AES.decrypt()를 사용합니다.
암호
- CryptoJS 라이브러리를 설치합니다.
npm install crypto-js
- @/utils/secret 폴더를 만들고 CryptoJS 라이브러리를 도입하고 암호화 및 암호 해독 기능 메서드를 캡슐화합니다.
import CryptoJS from 'crypto-js/crypto-js';
const key = CryptoJS.enc.Utf8.parse('123321'); // 密钥 后端提供
const iv = CryptoJS.enc.Utf8.parse(''); // 偏移量
/**
* AES加密 :字符串 key iv 返回base64
*/
export function Encrypt(word) {
const srcs = CryptoJS.enc.Utf8.parse(word);
const encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}
/**
* AES 解密 :字符串 key iv 返回base64
* */
export function Decrypt(word) {
const base64 = CryptoJS.enc.Base64.parse(word);
const src = CryptoJS.enc.Base64.stringify(base64);
const decrypt = CryptoJS.AES.decrypt(src, key, {
iv: iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
return CryptoJS.enc.Utf8.stringify(decrypt);
}
- 요청 전에 Axios에 캡슐화된 요청의 통합 처리를 암호화하는 암호화 및 암호 해독 방법을 도입합니다.
// 引入
import {
Encrypt, Decrypt } from '/@/utils/secret';
this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
// If cancel repeat request is turned on, then cancel repeat request is prohibited
// @ts-ignore
const {
ignoreCancelToken } = config.requestOptions;
const ignoreCancel =
ignoreCancelToken !== undefined
? ignoreCancelToken
: this.options.requestOptions?.ignoreCancelToken;
!ignoreCancel && axiosCanceler.addPending(config);
if (requestInterceptors && isFunction(requestInterceptors)) {
config = requestInterceptors(config, this.options);
}
// 关键代码:
// JSON加密,formData不加密(对需要处理的数据格式做判断)
if (Object.prototype.toString.call(config.data) != '[object FormData]') {
config.data = {
encryptedData: Encrypt(JSON.stringify(config.data)) }; // 加密传参,后端要求的传参:encryptedData:加密参数
}
return config;
}, undefined);
- 응답을 해독하기 위한 응답 전 처리 통합:
this.axiosInstance.interceptors.response.use(async (res: AxiosResponse<any>) => {
// 关键代码:
// 导出时数据格式为blob不解密(对需要处理的数据格式做判断)
if (Object.prototype.toString.call(res.data) != '[object Blob]') {
res.data = JSON.parse(Decrypt(res.data)); // 解密返回参数
}
const config = res.config;
if (res.data.code === 401) {
// 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
if (!isRefreshToken) {
isRefreshToken = true;
// 1. 获取到刷新token
if (getRefreshToken()) {
// 2. 进行刷新访问令牌
try {
const refreshTokenRes = await this.refreshToken();
// 2.1 刷新成功,则回放队列的请求 + 当前请求
setToken('Bearer ' + refreshTokenRes.data.data.accessToken);
(config as Recordable).headers.Authorization = getToken();
requestList.forEach((cb: any) => {
cb();
});
requestList = [];
return new Promise((resolve) => {
resolve(this.axiosInstance(config));
});
// res = await Promise.all([this.axiosInstance(config)])[0]
} catch (e) {
requestList.forEach((cb: any) => {
cb();
});
} finally {
requestList = [];
isRefreshToken = false;
}
}
} else {
// 添加到队列,等待刷新获取到新的令牌
return new Promise((resolve) => {
requestList.push(() => {
(config as Recordable).headers.Authorization = getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
resolve(this.axiosInstance(config));
});
});
}
}
res && axiosCanceler.removePending(res.config);
if (responseInterceptors && isFunction(responseInterceptors)) {
res = responseInterceptors(res);
}
return res;
}, undefined);
최종 효과
암호화된 매개변수 전송:
백엔드 반환 매개변수 암호화:
온라인 암호화 및 복호화 도구: https://www.mklab.cn/utils/aes