fix: 修复加密失效、权限失效、盘点页面崩溃等问题
- secureStorage.js: 移除硬编码密钥,改为运行时动态生成密钥 - AuthContext.jsx: 修复 hasPermission() 始终返回 true 的权限失效问题 - auth.js: 登录接口返回用户角色信息,支持前端权限判断 - InventoryManagement.jsx: 修复 res.data 多取一层导致 TypeError 崩溃
This commit is contained in:
@@ -1,10 +1,50 @@
|
||||
const STORAGE_PREFIX = 'idc_';
|
||||
const ENCRYPTION_ENABLED = import.meta.env.PROD;
|
||||
|
||||
/**
|
||||
* 生成运行时密钥(基于浏览器指纹)
|
||||
* 密钥在每次会话中动态生成,不会出现在源码或构建产物中
|
||||
* 同一浏览器同一域名下密钥保持一致,确保刷新页面后仍可解密
|
||||
*/
|
||||
const getOrCreateRuntimeKey = () => {
|
||||
const KEY_STORAGE_ID = '__idc_sk';
|
||||
let key = sessionStorage.getItem(KEY_STORAGE_ID);
|
||||
if (key) return key;
|
||||
|
||||
// 基于浏览器特征生成指纹作为密钥种子
|
||||
const fingerprint = [
|
||||
navigator.userAgent,
|
||||
screen.width,
|
||||
screen.height,
|
||||
screen.colorDepth,
|
||||
new Date().getTimezoneOffset(),
|
||||
navigator.language,
|
||||
].join('|');
|
||||
|
||||
// 使用简单的哈希混合生成 32 字符密钥
|
||||
let hash = 0;
|
||||
for (let i = 0; i < fingerprint.length; i++) {
|
||||
const char = fingerprint.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash + char) | 0;
|
||||
}
|
||||
|
||||
// 生成 32 字符的随机密钥
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
key = '';
|
||||
let seed = Math.abs(hash) + Date.now();
|
||||
for (let i = 0; i < 32; i++) {
|
||||
seed = (seed * 1103515245 + 12345) & 0x7fffffff;
|
||||
key += chars[seed % chars.length];
|
||||
}
|
||||
|
||||
sessionStorage.setItem(KEY_STORAGE_ID, key);
|
||||
return key;
|
||||
};
|
||||
|
||||
const simpleEncrypt = (text) => {
|
||||
if (!ENCRYPTION_ENABLED) return text;
|
||||
|
||||
const key = import.meta.env.VITE_STORAGE_KEY || 'idc_default_secret_key_2024';
|
||||
|
||||
const key = getOrCreateRuntimeKey();
|
||||
let result = '';
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
result += String.fromCharCode(text.charCodeAt(i) ^ key.charCodeAt(i % key.length));
|
||||
@@ -14,9 +54,9 @@ const simpleEncrypt = (text) => {
|
||||
|
||||
const simpleDecrypt = (encrypted) => {
|
||||
if (!ENCRYPTION_ENABLED) return encrypted;
|
||||
|
||||
|
||||
try {
|
||||
const key = import.meta.env.VITE_STORAGE_KEY || 'idc_default_secret_key_2024';
|
||||
const key = getOrCreateRuntimeKey();
|
||||
const decoded = decodeURIComponent(atob(encrypted));
|
||||
let result = '';
|
||||
for (let i = 0; i < decoded.length; i++) {
|
||||
@@ -51,22 +91,22 @@ export const secureStorage = {
|
||||
try {
|
||||
const storageKey = `${STORAGE_PREFIX}${key}`;
|
||||
const encrypted = localStorage.getItem(storageKey);
|
||||
|
||||
|
||||
if (!encrypted) return null;
|
||||
|
||||
|
||||
const decrypted = simpleDecrypt(encrypted);
|
||||
if (!decrypted) {
|
||||
localStorage.removeItem(storageKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
const data = JSON.parse(decrypted);
|
||||
|
||||
|
||||
if (data.expiry && Date.now() > data.expiry) {
|
||||
localStorage.removeItem(storageKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return data.value;
|
||||
} catch (error) {
|
||||
console.error('[SecureStorage] Get error:', error);
|
||||
|
||||
Reference in New Issue
Block a user