当前位置:网站首页>Are you still using localstorage directly? The thinnest in the whole network: secondary encapsulation of local storage (including encryption, decryption and expiration processing)
Are you still using localstorage directly? The thinnest in the whole network: secondary encapsulation of local storage (including encryption, decryption and expiration processing)
2022-06-21 09:32:00 【Feng Xin loves meat】
background
A lot of people are using it localStorage or sessionStorage I like to use it directly , Plaintext storage , Expose information directly to ; Browser , Although it can be handled in ordinary scenes and is simple and rough , But in case of special needs , For example, set the timing function , Can't achieve . It needs to be re encapsulated , In order to increase the sense of security in use , Encryption must be indispensable . For the convenience of the project , It is specially used to encapsulate routine operation .
The structure design
In encapsulating a series of operations stored locally API Before , First, a global object is prepared , Judge the specific operation , as follows :
interface globalConfig {
type: 'localStorage' | 'sessionStorage';
prefix: string;
expire: number;
isEncrypt: boolean;
}
const config: globalConfig = {
type: 'localStorage', // Storage type ,localStorage | sessionStorage
prefix: 'react-view-ui_0.0.1', // Version number
expire: 24 * 60, // Expiration time , The default is one day , In minutes
isEncrypt: true, // Encryption support 、 Decryption data processing
};
- type Indicates the storage type , by localStorage or sessionStorage ;
- prefix Represents the unique identifier of the view , If configured, it can be displayed in the browser view ;
- expire Indicates expiration time , The default is one day , In minutes ;
- isEncrypt Indicates support for encryption 、 Decryption data processing ;
Encryption preparation
Here is the use of crypto-js To handle encryption and decryption , You can download the package and import it first .
npm i --save-dev crypto-js
import CryptoJS from 'crypto-js';
Yes crypto-js Set the key and key offset , A private key can be passed through MD5 Encryption generation 16 Bit key acquisition .
const SECRET_KEY = CryptoJS.enc.Utf8.parse('3333e6e143439161'); // A hexadecimal number as a key
const SECRET_IV = CryptoJS.enc.Utf8.parse('e3bbe7e3ba84431a'); // Hexadecimal number as key offset
encryption
const encrypt = (data: object | string): string => {
// encryption
if (typeof data === 'object') {
try {
data = JSON.stringify(data);
} catch (e) {
throw new Error('encrypt error' + e);
}
}
const dataHex = CryptoJS.enc.Utf8.parse(data);
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
iv: SECRET_IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.ciphertext.toString();
};
Decrypt
const decrypt = (data: string) => {
// Decrypt
const encryptedHexStr = CryptoJS.enc.Hex.parse(data);
const str = CryptoJS.enc.Base64.stringify(encryptedHexStr);
const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
iv: SECRET_IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
};
these two items. API All are stored locally value Pass as a parameter , In this way, encryption and decryption are realized .
Process the incoming data 、 It needs to be decrypted when changing ;
Encryption is required when data needs to be transferred out .
The core API Realization
setStorage Set the value
Storage The expiration time setting is not supported , To support setting expiration time , You can follow the example of Cookie How to do it ,setStorage(key, value, expire) Method , Receive three parameters , The third parameter is to set the expiration time , In relative time , Units of minutes , Type check the passed parameters . You can set a uniform expiration time , The expiration time of a single value can also be configured separately .
const setStorage = (key: string, value: any, expire: number = 24 * 60): boolean => {
// The set value
if (value === '' || value === null || value === undefined) {
// Null reset
value = null;
}
if (isNaN(expire) || expire < 0) {
// Rationality judgment of expiration time value
throw new Error('Expire must be a number');
}
const data = {
value, // Stored value
time: Date.now(), // Storage date
expire: Date.now() + 1000 * 60 * expire, // Expiration time
};
// Whether encryption is required , Determine whether to load encrypted data or original data
window[config.type].setItem(
autoAddPreFix(key),
config.isEncrypt ? encrypt(JSON.stringify(data)) : JSON.stringify(data),
);
return true;
};
getStorageFromKey according to key obtain value
First of all, we have to deal with key Whether there is a judgment , To prevent an error from getting a nonexistent value . Further extension of the acquisition method , It can be obtained as long as it is within the validity period Storage value , If it expires, the value will be deleted directly , And back to null.
const getStorageFromKey = (key: string) => {
// Get the specified value
if (config.prefix) {
key = autoAddPreFix(key);
}
if (!window[config.type].getItem(key)) {
// There is no judgment
return null;
}
const storageVal = config.isEncrypt
? JSON.parse(decrypt(window[config.type].getItem(key) as string))
: JSON.parse(window[config.type].getItem(key) as string);
const now = Date.now();
if (now >= storageVal.expire) {
// Expired destruction
removeStorageFromKey(key);
return null;
// No expiration return value
} else {
return storageVal.value;
}
};
getAllStorage Get all stored values
const getAllStorage = () => {
// Get all values
const storageList: any = {
};
const keys = Object.keys(window[config.type]);
keys.forEach((key) => {
const value = getStorageFromKey(key);
if (value !== null) {
// If the value does not expire , Add to list
storageList[key] = value;
}
});
return storageList;
};
getStorageLength Get the number of stored values
const getStorageLength = () => {
// Get value list length
return window[config.type].length;
};
removeStorageFromKey according to key Delete stored values
const removeStorageFromKey = (key: string) => {
// Delete value
if (config.prefix) {
key = autoAddPreFix(key);
}
window[config.type].removeItem(key);
};
clearStorage Empty the storage list
const clearStorage = () => {
window[config.type].clear();
};
autoAddPreFix Based on global configuration prefix Parameter to add prefix
const autoAddPreFix = (key: string) => {
// add prefix , Keep the browser Application View uniqueness
const prefix = config.prefix || '';
return `${
prefix}_${
key}`;
};
This is a function that does not export , Internal tool functions encapsulated as a whole , stay setStorage、getStorageFromKey、removeStorageFromKey Will use .
Export function list
Provides 6 The processing power of a function , It is sufficient to deal with most operations of the actual business .
export {
setStorage,
getStorageFromKey,
getAllStorage,
getStorageLength,
removeStorageFromKey,
clearStorage,
};
Use
Use... In real business , Then import the function , Let's first look at the writer's file directory :
The actual use :
import {
setStorage,
getStorageFromKey,
getAllStorage,
getStorageLength,
removeStorageFromKey,
clearStorage
} from '../../_util/storage/config'
setStorage('name', 'fx', 1)
setStorage('age', {
now: 18 }, 100000)
setStorage('history', [1, 2, 3], 100000)
console.log(getStorageFromKey('name'))
removeStorageFromKey('name')
console.log(getStorageFromKey('name'))
console.log(getStorageLength());
console.log(getAllStorage());
clearStorage();
Next, take a look at the browser view :

You can see ,key Processed and added config.prefix The prefix of , With uniqueness .
value It has been encrypted .
Take another look at the passage get Method to obtain the console value output :

Perfect. , The actual business will clear the prefix and return it for processing , There are prefix binding and encryption processing in the view , Ensure the security of local storage .
Complete code
config.ts:
import {
encrypt, decrypt } from './encry';
import {
globalConfig } from './interface';
const config: globalConfig = {
type: 'localStorage', // Storage type ,localStorage | sessionStorage
prefix: 'react-view-ui_0.0.1', // Version number
expire: 24 * 60, // Expiration time , The default is one day , In minutes
isEncrypt: true, // Encryption support 、 Decryption data processing
};
const setStorage = (key: string, value: any, expire: number = 24 * 60): boolean => {
// The set value
if (value === '' || value === null || value === undefined) {
// Null reset
value = null;
}
if (isNaN(expire) || expire < 0) {
// Rationality judgment of expiration time value
throw new Error('Expire must be a number');
}
const data = {
value, // Stored value
time: Date.now(), // Storage date
expire: Date.now() + 1000 * 60 * expire, // Expiration time
};
// Whether encryption is required , Determine whether to load encrypted data or original data
window[config.type].setItem(
autoAddPreFix(key),
config.isEncrypt ? encrypt(JSON.stringify(data)) : JSON.stringify(data),
);
return true;
};
const getStorageFromKey = (key: string) => {
// Get the specified value
if (config.prefix) {
key = autoAddPreFix(key);
}
if (!window[config.type].getItem(key)) {
// There is no judgment
return null;
}
const storageVal = config.isEncrypt
? JSON.parse(decrypt(window[config.type].getItem(key) as string))
: JSON.parse(window[config.type].getItem(key) as string);
const now = Date.now();
if (now >= storageVal.expire) {
// Expired destruction
removeStorageFromKey(key);
return null;
// No expiration return value
} else {
return storageVal.value;
}
};
const getAllStorage = () => {
// Get all values
const storageList: any = {
};
const keys = Object.keys(window[config.type]);
keys.forEach((key) => {
const value = getStorageFromKey(autoRemovePreFix(key));
if (value !== null) {
// If the value does not expire , Add to list
storageList[autoRemovePreFix(key)] = value;
}
});
return storageList;
};
const getStorageLength = () => {
// Get value list length
return window[config.type].length;
};
const removeStorageFromKey = (key: string) => {
// Delete value
if (config.prefix) {
key = autoAddPreFix(key);
}
window[config.type].removeItem(key);
};
const clearStorage = () => {
window[config.type].clear();
};
const autoAddPreFix = (key: string) => {
// add prefix , Keep it unique
const prefix = config.prefix || '';
return `${
prefix}_${
key}`;
};
const autoRemovePreFix = (key: string) => {
// Delete prefix , Add, delete, modify, etc
const lineIndex = config.prefix.length + 1;
return key.substr(lineIndex);
};
export {
setStorage,
getStorageFromKey,
getAllStorage,
getStorageLength,
removeStorageFromKey,
clearStorage,
};
encry.ts:
import CryptoJS from 'crypto-js';
const SECRET_KEY = CryptoJS.enc.Utf8.parse('3333e6e143439161'); // A hexadecimal number as a key
const SECRET_IV = CryptoJS.enc.Utf8.parse('e3bbe7e3ba84431a'); // Hexadecimal number as key offset
const encrypt = (data: object | string): string => {
// encryption
if (typeof data === 'object') {
try {
data = JSON.stringify(data);
} catch (e) {
throw new Error('encrypt error' + e);
}
}
const dataHex = CryptoJS.enc.Utf8.parse(data);
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
iv: SECRET_IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.ciphertext.toString();
};
const decrypt = (data: string) => {
// Decrypt
const encryptedHexStr = CryptoJS.enc.Hex.parse(data);
const str = CryptoJS.enc.Base64.stringify(encryptedHexStr);
const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
iv: SECRET_IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
};
export {
encrypt, decrypt };
interface.ts:
interface globalConfig {
type: 'localStorage' | 'sessionStorage';
prefix: string;
expire: number;
isEncrypt: boolean;
}
export type {
globalConfig };
summary
In front-end development, it is not only common but also unsafe to use plaintext storage locally , Secondary encapsulation of local storage can improve security , And with API Support for , It is easier to store operations locally .
边栏推荐
- 一条命令开启监控之旅!
- Retrofit Extended reading
- How to connect the Internet - FTTH
- Application configuration management, basic principle analysis
- finally block can not complete normally
- 信号功率谱估计
- 115. secondary packaging of table components
- Audio and video synchronization knowledge points you must pay attention to:
- R language through rprofile Site file, user-defined configuration of R language development environment startup parameters, shutdown parameters, user-defined specified cran local image source download
- Waiting in webdriver
猜你喜欢

Wechat applet
![[vs], [usage problem], [solution] when VS2010 is opened, it stays in the startup interface](/img/04/a7455760caa4fc0480a034de1e24b8.png)
[vs], [usage problem], [solution] when VS2010 is opened, it stays in the startup interface

智能制造的下一站:云原生+边缘计算双轮驱动

Solve the problem of error when typescript object gets value

Binary search (integer binary)

Storage of floating point numbers in C language in memory

Zhihu wanzan: what kind of programmers are still wanted by the company after the age of 35? Breaking the "middle age crisis" of programmers

Unity中的地平面简介

【实战】STM32MP157开发教程之FreeRTOS系统篇6:FreeRTOS 列表和列表项

Job hopping is better than promotion
随机推荐
Stm32mp1 cortex M4 development part 12: expansion board vibration motor control
【实战】STM32 FreeRTOS移植系列教程4:FreeRTOS 软件定时器
Embedded remote post, part-time job, order receiving, crowdsourcing platform
【云原生 | Kubernetes篇】Kubernetes 配置(十五)
【实战】STM32 FreeRTOS移植系列教程7:FreeRTOS 事件标志组
Telecommuting Market Research Report
Application configuration management, basic principle analysis
The skill of using ADB and the principle of USB communication
多态&Class对象&注册工厂&反射&动态代理
[practice] STM32 FreeRTOS migration series tutorial 5:freertos message queue
[practice] stm32mp157 development tutorial FreeRTOS system 6: FreeRTOS list and list items
TC software detailed design document (mobile group control)
The most authoritative Lei niukesi in history --- embedded Ai Road line [yyds]
TC软件概要设计文档(手机群控)
Token, cookie and session
【C】 [time operation] time operation in C language
Source insight shortcut key cross reference
R language uses as The character function converts date vector data to string (character) vector data
C#中的list操作入门
Three key directories in R language and their corresponding priorities: R_ Home directory, user directory, current working directory, files read by R's startup process