feat(login): 加密存储登录参数

- 引入 crypto-js 库实现 AES 加密功能
- 新增 utils/crypto.ts 工具文件,提供加密解密方法
- 修改登录表单,对记住密码功能中的用户名和密码进行加密存储
- 更新 package.json 和 lock 文件,添加相关依赖和类型定义
- 优化解密逻辑,增加错误处理和空值判断
- 使用加密方法替换原有的 JSON 字符串存储方式
master
钟良源 3 months ago
parent 17361c3285
commit 7b64cedf2c

@ -35,6 +35,7 @@
"copy-to-clipboard": "^3.3.1", "copy-to-clipboard": "^3.3.1",
"cron-parser": "^5.3.1", "cron-parser": "^5.3.1",
"cronstrue": "^3.2.0", "cronstrue": "^3.2.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"echarts": "^5.6.0", "echarts": "^5.6.0",
"echarts-for-react": "^3.0.2", "echarts-for-react": "^3.0.2",
@ -55,6 +56,7 @@
}, },
"devDependencies": { "devDependencies": {
"@svgr/webpack": "^5.5.0", "@svgr/webpack": "^5.5.0",
"@types/crypto-js": "^4.2.2",
"@types/node": "16.11.7", "@types/node": "16.11.7",
"@types/react": "17.0.2", "@types/react": "17.0.2",
"@types/react-dom": "^17.0.2", "@types/react-dom": "^17.0.2",

@ -71,6 +71,9 @@ importers:
cronstrue: cronstrue:
specifier: ^3.2.0 specifier: ^3.2.0
version: 3.2.0 version: 3.2.0
crypto-js:
specifier: ^4.2.0
version: 4.2.0
dayjs: dayjs:
specifier: ^1.11.13 specifier: ^1.11.13
version: 1.11.13 version: 1.11.13
@ -126,6 +129,9 @@ importers:
'@svgr/webpack': '@svgr/webpack':
specifier: ^5.5.0 specifier: ^5.5.0
version: 5.5.0 version: 5.5.0
'@types/crypto-js':
specifier: ^4.2.2
version: 4.2.2
'@types/node': '@types/node':
specifier: 16.11.7 specifier: 16.11.7
version: 16.11.7 version: 16.11.7
@ -1478,6 +1484,9 @@ packages:
'@types/cookie@0.3.3': '@types/cookie@0.3.3':
resolution: {integrity: sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==} resolution: {integrity: sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==}
'@types/crypto-js@4.2.2':
resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==}
'@types/d3-color@3.1.3': '@types/d3-color@3.1.3':
resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
@ -2180,6 +2189,9 @@ packages:
crypto-browserify@3.12.0: crypto-browserify@3.12.0:
resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==}
crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
css-functions-list@3.2.3: css-functions-list@3.2.3:
resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==} resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==}
engines: {node: '>=12 || >=16'} engines: {node: '>=12 || >=16'}
@ -7068,6 +7080,8 @@ snapshots:
'@types/cookie@0.3.3': {} '@types/cookie@0.3.3': {}
'@types/crypto-js@4.2.2': {}
'@types/d3-color@3.1.3': {} '@types/d3-color@3.1.3': {}
'@types/d3-drag@3.0.7': '@types/d3-drag@3.0.7':
@ -7968,6 +7982,8 @@ snapshots:
randombytes: 2.1.0 randombytes: 2.1.0
randomfill: 1.0.4 randomfill: 1.0.4
crypto-js@4.2.0: {}
css-functions-list@3.2.3: {} css-functions-list@3.2.3: {}
css-select-base-adapter@0.1.1: {} css-select-base-adapter@0.1.1: {}

@ -14,6 +14,7 @@ import useStorage from '@/utils/useStorage';
import useLocale from '@/utils/useLocale'; import useLocale from '@/utils/useLocale';
import locale from './locale'; import locale from './locale';
import styles from './style/index.module.less'; import styles from './style/index.module.less';
import { encryptLoginParams, decryptLoginParams } from '@/utils/crypto';
export default function LoginForm() { export default function LoginForm() {
const formRef = useRef<FormInstance>(); const formRef = useRef<FormInstance>();
@ -29,7 +30,7 @@ export default function LoginForm() {
function afterLoginSuccess(params, token?: string) { function afterLoginSuccess(params, token?: string) {
// 记住密码 // 记住密码
if (rememberPassword) { if (rememberPassword) {
setLoginParams(JSON.stringify(params)); setLoginParams(encryptLoginParams(params));
} }
else { else {
removeLoginParams(); removeLoginParams();
@ -63,14 +64,16 @@ export default function LoginForm() {
}); });
} }
// 读取 localStorage设置初始值 // 读取 localStorage,设置初始值
useEffect(() => { useEffect(() => {
const rememberPassword = !!loginParams; const rememberPassword = !!loginParams;
setRememberPassword(rememberPassword); setRememberPassword(rememberPassword);
if (formRef.current && rememberPassword) { if (formRef.current && rememberPassword) {
const parseParams = JSON.parse(loginParams); const parseParams = decryptLoginParams(loginParams);
if (parseParams) {
formRef.current.setFieldsValue(parseParams); formRef.current.setFieldsValue(parseParams);
} }
}
}, [loginParams]); }, [loginParams]);
return ( return (

@ -0,0 +1,69 @@
import CryptoJS from 'crypto-js';
// 加密密钥 - 建议从环境变量读取,这里使用固定密钥作为示例
const SECRET_KEY = 'flow-platform-2025-secret-key';
/**
* AES
* @param data JSON
* @returns
*/
export function encrypt(data: any): string {
try {
const jsonString = typeof data === 'string' ? data : JSON.stringify(data);
const encrypted = CryptoJS.AES.encrypt(jsonString, SECRET_KEY).toString();
return encrypted;
} catch (error) {
console.error('加密失败:', error);
throw error;
}
}
/**
* AES
* @param encryptedData
* @returns JSON
*/
export function decrypt(encryptedData: string): any {
try {
const bytes = CryptoJS.AES.decrypt(encryptedData, SECRET_KEY);
const decryptedString = bytes.toString(CryptoJS.enc.Utf8);
if (!decryptedString) {
throw new Error('解密失败:无法解析数据');
}
// 尝试解析为 JSON如果失败则返回原始字符串
try {
return JSON.parse(decryptedString);
} catch {
return decryptedString;
}
} catch (error) {
console.error('解密失败:', error);
throw error;
}
}
/**
*
* @param params username password
* @returns
*/
export function encryptLoginParams(params: { username: string; password: string }): string {
return encrypt(params);
}
/**
*
* @param encryptedParams
* @returns username password
*/
export function decryptLoginParams(encryptedParams: string): { username: string; password: string } | null {
try {
return decrypt(encryptedParams);
} catch (error) {
console.error('解密登录参数失败:', error);
return null;
}
}
Loading…
Cancel
Save