1.新增缓存加密
2.新增pinia全局状态管理
This commit is contained in:
Huang 2022-06-10 15:46:39 +08:00
parent 9395f17bf7
commit 76afc21f12
13 changed files with 387 additions and 2 deletions

View File

@ -47,7 +47,9 @@
"@dcloudio/uni-mp-toutiao": "^3.0.0-alpha-3041420220607001",
"@dcloudio/uni-mp-weixin": "^3.0.0-alpha-3041420220607001",
"@dcloudio/uni-quickapp-webview": "^3.0.0-alpha-3041420220607001",
"crypto-js": "^4.1.1",
"lodash-es": "^4.17.21",
"pinia": "^2.0.14",
"vue": "^3.2.37",
"vue-i18n": "^9.1.10"
},
@ -57,6 +59,7 @@
"@dcloudio/uni-automator": "^3.0.0-alpha-3041420220607001",
"@dcloudio/uni-cli-shared": "^3.0.0-alpha-3041420220607001",
"@dcloudio/vite-plugin-uni": "^3.0.0-alpha-3041420220607001",
"@types/crypto-js": "^4.1.1",
"@types/lodash-es": "^4.17.6",
"@types/node": "^17.0.41",
"@typescript-eslint/eslint-plugin": "^5.27.1",

58
pnpm-lock.yaml generated
View File

@ -18,10 +18,12 @@ specifiers:
'@dcloudio/uni-mp-weixin': ^3.0.0-alpha-3041420220607001
'@dcloudio/uni-quickapp-webview': ^3.0.0-alpha-3041420220607001
'@dcloudio/vite-plugin-uni': ^3.0.0-alpha-3041420220607001
'@types/crypto-js': ^4.1.1
'@types/lodash-es': ^4.17.6
'@types/node': ^17.0.41
'@typescript-eslint/eslint-plugin': ^5.27.1
'@typescript-eslint/parser': ^5.27.1
crypto-js: ^4.1.1
eslint: ^8.17.0
eslint-config-prettier: ^8.5.0
eslint-plugin-prettier: ^4.0.0
@ -30,6 +32,7 @@ specifiers:
lint-staged: ^13.0.0
lodash-es: ^4.17.21
mrm: ^4.0.0
pinia: ^2.0.14
postcss: ^8.4.14
prettier: ^2.6.2
sass: ^1.52.2
@ -53,7 +56,9 @@ dependencies:
'@dcloudio/uni-mp-toutiao': registry.npmmirror.com/@dcloudio/uni-mp-toutiao/3.0.0-alpha-3041420220607001_postcss@8.4.14+vue@3.2.37
'@dcloudio/uni-mp-weixin': registry.npmmirror.com/@dcloudio/uni-mp-weixin/3.0.0-alpha-3041420220607001_postcss@8.4.14+vue@3.2.37
'@dcloudio/uni-quickapp-webview': registry.npmmirror.com/@dcloudio/uni-quickapp-webview/3.0.0-alpha-3041420220607001_postcss@8.4.14+vue@3.2.37
crypto-js: registry.npmmirror.com/crypto-js/4.1.1
lodash-es: registry.npmmirror.com/lodash-es/4.17.21
pinia: registry.npmmirror.com/pinia/2.0.14_vcmyupim4cga7k7f5hngmth5py
vue: registry.npmmirror.com/vue/3.2.37
vue-i18n: registry.npmmirror.com/vue-i18n/9.1.10_vue@3.2.37
@ -63,6 +68,7 @@ devDependencies:
'@dcloudio/uni-automator': registry.npmmirror.com/@dcloudio/uni-automator/3.0.0-alpha-3041420220607001_postcss@8.4.14+vue@3.2.37
'@dcloudio/uni-cli-shared': registry.npmmirror.com/@dcloudio/uni-cli-shared/3.0.0-alpha-3041420220607001_postcss@8.4.14+vue@3.2.37
'@dcloudio/vite-plugin-uni': registry.npmmirror.com/@dcloudio/vite-plugin-uni/3.0.0-alpha-3041420220607001_v3gufi5q4zlo7bdphizzdh2mhm
'@types/crypto-js': registry.npmmirror.com/@types/crypto-js/4.1.1
'@types/lodash-es': registry.npmmirror.com/@types/lodash-es/4.17.6
'@types/node': registry.npmmirror.com/@types/node/17.0.41
'@typescript-eslint/eslint-plugin': registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.27.1_aq7uryhocdbvbqum33pitcm3y4
@ -1309,6 +1315,12 @@ packages:
defer-to-connect: registry.npmmirror.com/defer-to-connect/1.1.3
dev: true
registry.npmmirror.com/@types/crypto-js/4.1.1:
resolution: {integrity: sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/crypto-js/-/crypto-js-4.1.1.tgz}
name: '@types/crypto-js'
version: 4.1.1
dev: true
registry.npmmirror.com/@types/eslint/8.4.2:
resolution: {integrity: sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/eslint/-/eslint-8.4.2.tgz}
name: '@types/eslint'
@ -2534,6 +2546,12 @@ packages:
which: registry.npmmirror.com/which/2.0.2
dev: true
registry.npmmirror.com/crypto-js/4.1.1:
resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/crypto-js/-/crypto-js-4.1.1.tgz}
name: crypto-js
version: 4.1.1
dev: false
registry.npmmirror.com/crypto-random-string/1.0.0:
resolution: {integrity: sha512-GsVpkFPlycH7/fRR7Dhcmnoii54gV1nz7y4CWyeFS14N+JVBBhY+r8amRHE4BwSYal7BPTDp8isvAlCxyFt3Hg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz}
name: crypto-random-string
@ -5231,6 +5249,27 @@ packages:
engines: {node: '>=4'}
dev: true
registry.npmmirror.com/pinia/2.0.14_vcmyupim4cga7k7f5hngmth5py:
resolution: {integrity: sha512-0nPuZR4TetT/WcLN+feMSjWJku3SQU7dBbXC6uw+R6FLQJCsg+/0pzXyD82T1FmAYe0lsx+jnEDQ1BLgkRKlxA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/pinia/-/pinia-2.0.14.tgz}
id: registry.npmmirror.com/pinia/2.0.14
name: pinia
version: 2.0.14
peerDependencies:
'@vue/composition-api': ^1.4.0
typescript: '>=4.4.4'
vue: ^2.6.14 || ^3.2.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
typescript:
optional: true
dependencies:
'@vue/devtools-api': registry.npmmirror.com/@vue/devtools-api/6.1.4
typescript: registry.npmmirror.com/typescript/4.7.3
vue: registry.npmmirror.com/vue/3.2.37
vue-demi: registry.npmmirror.com/vue-demi/0.13.1_vue@3.2.37
dev: false
registry.npmmirror.com/postcss-import/14.1.0_postcss@8.4.14:
resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/postcss-import/-/postcss-import-14.1.0.tgz}
id: registry.npmmirror.com/postcss-import/14.1.0
@ -6316,7 +6355,6 @@ packages:
version: 4.7.3
engines: {node: '>=4.2.0'}
hasBin: true
dev: true
registry.npmmirror.com/unique-random-array/1.0.0:
resolution: {integrity: sha512-vtj2yltjcHPa69nFjNJ3xnhsEwE8pMyjqUQDw2myz/iSezqf4YCAcygwFQEsOgMid5VNW/dCPbnb2BcmaDCCKg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/unique-random-array/-/unique-random-array-1.0.0.tgz}
@ -6561,6 +6599,24 @@ packages:
optionalDependencies:
fsevents: registry.npmmirror.com/fsevents/2.3.2
registry.npmmirror.com/vue-demi/0.13.1_vue@3.2.37:
resolution: {integrity: sha512-xmkJ56koG3ptpLnpgmIzk9/4nFf4CqduSJbUM0OdPoU87NwRuZ6x49OLhjSa/fC15fV+5CbEnrxU4oyE022svg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.1.tgz}
id: registry.npmmirror.com/vue-demi/0.13.1
name: vue-demi
version: 0.13.1
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
dependencies:
vue: registry.npmmirror.com/vue/3.2.37
dev: false
registry.npmmirror.com/vue-eslint-parser/9.0.2_eslint@8.17.0:
resolution: {integrity: sha512-uCPQwTGjOtAYrwnU+76pYxalhjsh7iFBsHwBqDHiOPTxtICDaraO4Szw54WFTNZTAEsgHHzqFOu1mmnBOBRzDA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.0.2.tgz}
id: registry.npmmirror.com/vue-eslint-parser/9.0.2

5
src/enums/cacheEnum.ts Normal file
View File

@ -0,0 +1,5 @@
// token key
export const TOKEN_KEY = 'TOKEN__';
// user info key
export const USER_INFO_KEY = 'USER__INFO__';

3
src/env.d.ts vendored
View File

@ -1,5 +1,7 @@
// / <reference types="vite/client" />
import { DEFAULT_PREFIX_KEY } from '@/settings/encryptionSetting';
declare module '*.vue' {
import { DefineComponent } from 'vue';
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
@ -15,6 +17,7 @@ interface ImportMetaEnv {
readonly VITE_UPLOAD_URL: string;
readonly VITE_PROD: boolean;
readonly VITE_DEV: boolean;
readonly VITE_APP_CACHE_PREFIX: string;
}
interface ImportMeta {

View File

@ -2,10 +2,16 @@ import { createSSRApp } from 'vue';
import App from './App.vue';
import 'virtual:windi.css';
import { setupInterceptors } from '@/utils/interceptors';
import { setupStore } from '@/state';
setupInterceptors();
export function createApp() {
const app = createSSRApp(App);
// Configure store
setupStore(app);
return {
app,
};

View File

@ -11,6 +11,7 @@
</label>
<button @tap="submit">login</button>
{{ loginType }}
<view>{{ token }}---</view>
</view>
</view>
</template>
@ -18,17 +19,22 @@
<script setup lang="ts">
import { reactive, ref } from 'vue';
import { defHttp } from '@/utils/http/index';
import { useUserStore } from '@/state/modules/user';
const form = reactive({
email: 'catch@admin.com',
password: 'catchadmin',
});
const loginType = ref('');
const token = ref<string>('');
const userStore = useUserStore();
const submit = () => {
defHttp
.post('/login', form)
.then((res: any) => {
loginType.value = '登录成功';
console.log(res.message);
console.log(res);
userStore.setToken(res.data.token);
token.value = userStore.getToken;
})
.catch((err: any) => {
loginType.value = '登录失败';

View File

@ -0,0 +1,15 @@
import { getPkgVersion, isDevMode } from '@/utils/env';
// System default cache time, in seconds
export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;
const PREFIX = import.meta.env.VITE_APP_CACHE_PREFIX || 'UNI_APP_VUE3_TS';
export const DEFAULT_PREFIX_KEY = `${PREFIX}${getPkgVersion()}`;
// aes encryption key
export const cacheCipher = {
key: 'aQ0{gD1@c_0@oH5:',
iv: 'aF0#gC_$hE1$eA1!',
};
// Whether the system cache is encrypted using aes
export const enableStorageEncryption = !isDevMode();

10
src/state/index.ts Normal file
View File

@ -0,0 +1,10 @@
import type { App } from 'vue';
import { createPinia } from 'pinia';
const store = createPinia();
export function setupStore(app: App<Element>) {
app.use(store);
}
export { store };

23
src/state/modules/user.ts Normal file
View File

@ -0,0 +1,23 @@
import { defineStore } from 'pinia';
import { getCache, setCache } from '@/utils/catch';
import { TOKEN_KEY } from '@/enums/cacheEnum';
interface UserState {
token?: string;
}
export const useUserStore = defineStore({
id: 'user',
state: (): UserState => ({
token: undefined,
}),
getters: {
getToken: (state) => state.token || getCache<string>(TOKEN_KEY),
},
actions: {
setToken(token: string) {
setCache(TOKEN_KEY, token);
this.token = token;
},
},
});

33
src/utils/catch/index.ts Normal file
View File

@ -0,0 +1,33 @@
import { createStorage, CreateStorageParams } from './storageCache';
import {
cacheCipher,
DEFAULT_CACHE_TIME,
DEFAULT_PREFIX_KEY,
enableStorageEncryption,
} from '@/settings/encryptionSetting';
const options: Partial<CreateStorageParams> = {
prefixKey: DEFAULT_PREFIX_KEY,
key: cacheCipher.key,
iv: cacheCipher.iv,
hasEncrypt: enableStorageEncryption,
timeout: DEFAULT_CACHE_TIME,
};
export const storage = createStorage(options);
export function setCache(key: string, value: any, expire?: number | null): void {
storage.set(key, value, expire);
}
export function getCache<T = any>(key: string): T {
return storage.get<T>(key);
}
export function removeCache(key: string): void {
return storage.remove(key);
}
export function clearCache(): void {
return storage.clear();
}

View File

@ -0,0 +1,112 @@
import { cacheCipher } from '@/settings/encryptionSetting';
import type { EncryptionParams } from '@/utils/cipher';
import { AesEncryption } from '@/utils/cipher';
import { isNullOrUnDef } from '@/utils/is';
export interface CreateStorageParams extends EncryptionParams {
prefixKey: string;
hasEncrypt: boolean;
timeout?: number | null;
}
export const createStorage = ({
prefixKey = '',
key = cacheCipher.key,
iv = cacheCipher.iv,
timeout = null,
hasEncrypt = true,
}: Partial<CreateStorageParams> = {}) => {
if (hasEncrypt && [key.length, iv.length].some((item) => item !== 16)) {
throw new Error('When hasEncrypt is true, the key or iv must be 16 bits!');
}
const encryption = new AesEncryption({ key, iv });
/**
* Cache class
* Construction parameters can be passed into sessionStorage, localStorage,
* @class Cache
* @example
*/
class Storage {
private prefixKey?: string;
private encryption: AesEncryption;
private hasEncrypt: boolean;
/**
*
* @param {*} storage
*/
constructor() {
this.prefixKey = prefixKey;
this.encryption = encryption;
this.hasEncrypt = hasEncrypt;
}
private getKey(key: string) {
return `${this.prefixKey}${key}`.toUpperCase();
}
/**
* Set cache
* @param {string} key
* @param {*} value
* @param {*} expire Expiration time in seconds
* @memberof Cache
*/
set(key: string, value: any, expire: number | null = timeout) {
try {
const stringData = JSON.stringify({
value,
time: Date.now(),
expire: !isNullOrUnDef(expire) ? new Date().getTime() + expire * 1000 : null,
});
const stringifyValue = this.hasEncrypt
? this.encryption.encryptByAES(stringData)
: stringData;
uni.setStorageSync(this.getKey(key), stringifyValue);
} catch (err) {
throw new Error(`setStorageSync error: ${err}`);
}
}
/**
* Read cache
* @param {string} key
* @param {*} def
* @memberof Cache
*/
get<T = any>(key: string, def: any = null): T {
const val = uni.getStorageSync(this.getKey(key));
if (!val) return def;
try {
const decVal = this.hasEncrypt ? this.encryption.decryptByAES(val) : val;
const data = JSON.parse(decVal);
const { value, expire } = data;
if (isNullOrUnDef(expire) || expire < new Date().getTime()) {
this.remove(key);
return def;
}
return value;
} catch (e) {
return def;
}
}
/**
* Delete cache based on key
* @param {string} key
* @memberof Cache
*/
remove(key: string) {
uni.removeStorageSync(this.getKey(key));
}
/**
* Delete all caches of this instance
*/
clear(): void {
uni.clearStorageSync();
}
}
return new Storage();
};

70
src/utils/cipher.ts Normal file
View File

@ -0,0 +1,70 @@
import { encrypt, decrypt } from 'crypto-js/aes';
import { parse } from 'crypto-js/enc-utf8';
import pkcs7 from 'crypto-js/pad-pkcs7';
import ECB from 'crypto-js/mode-ecb';
import md5 from 'crypto-js/md5';
import UTF8 from 'crypto-js/enc-utf8';
import Base64 from 'crypto-js/enc-base64';
export interface EncryptionParams {
key: string;
iv: string;
}
/**
* AES
*/
export class AesEncryption {
private key;
private iv;
constructor(opt: Partial<EncryptionParams> = {}) {
const { key, iv } = opt;
if (key) {
this.key = parse(key);
}
if (iv) {
this.iv = parse(iv);
}
}
get getOptions() {
return {
mode: ECB,
padding: pkcs7,
iv: this.iv,
};
}
encryptByAES(cipherText: string) {
return encrypt(cipherText, this.key!, this.getOptions).toString();
}
decryptByAES(cipherText: string) {
return decrypt(cipherText, this.key!, this.getOptions).toString(UTF8);
}
}
/**
* Base64加密
* @param cipherText
*/
export function encryptByBase64(cipherText: string) {
return UTF8.parse(cipherText).toString(Base64);
}
/**
* Base64解密
* @param cipherText
*/
export function decodeByBase64(cipherText: string) {
return Base64.parse(cipherText).toString(UTF8);
}
/**
* MD5加密
* @param password
*/
export function encryptByMd5(password: string) {
return md5(password).toString();
}

43
src/utils/env.ts Normal file
View File

@ -0,0 +1,43 @@
import pkg from '../../package.json';
// Generate cache key according to version
export function getPkgVersion() {
return `${`__${pkg.version}`}__`.toUpperCase();
}
/**
* @description: Development mode
*/
export const devMode = 'development';
/**
* @description: Production mode
*/
export const prodMode = 'production';
/**
* @description: Get environment variables
* @returns:
* @example:
*/
export function getEnv(): string {
return isDevMode() ? devMode : prodMode;
}
/**
* @description: Is it a development mode
* @returns:
* @example:
*/
export function isDevMode(): boolean {
return import.meta.env.VITE_DEV;
}
/**
* @description: Is it a production mode
* @returns:
* @example:
*/
export function isProdMode(): boolean {
return import.meta.env.VITE_PROD;
}