Compare commits
	
		
			16 Commits
		
	
	
		
			af8ed90ab3
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| bae8275b11 | |||
| 0a0ffbdb23 | |||
| 557cd99b20 | |||
| 8b4312782d | |||
| f8af24506b | |||
| f1024941ed | |||
| 98c8a2ad86 | |||
| 8ac11bbd28 | |||
| 05f0373834 | |||
| e0bf83f062 | |||
| fdf6d3ac0a | |||
| 54672a5574 | |||
| 9ba45c37c2 | |||
| 24f091ac79 | |||
| a457dbabe9 | |||
| c546ad2459 | 
							
								
								
									
										65
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,66 @@ | ||||
| dist | ||||
| node_modules | ||||
|  | ||||
| # mac | ||||
| .DS_Store | ||||
| .env | ||||
|  | ||||
| .env* | ||||
| !.env*example | ||||
|  | ||||
| dist | ||||
| build | ||||
| logs | ||||
|  | ||||
| .turbo | ||||
|  | ||||
| pack-dist | ||||
|  | ||||
| # astro | ||||
| .astro | ||||
|  | ||||
| # next | ||||
| .next | ||||
|  | ||||
| # nuxt | ||||
| .nuxt | ||||
|  | ||||
| # vercel | ||||
| .vercel | ||||
|  | ||||
| # vuepress | ||||
| .vuepress/dist | ||||
|  | ||||
| # coverage | ||||
| coverage/ | ||||
|  | ||||
| # typescript | ||||
| *.tsbuildinfo | ||||
|  | ||||
| # debug logs | ||||
| *.log | ||||
| *.tmp | ||||
|  | ||||
| # vscode | ||||
| .vscode/* | ||||
| !.vscode/settings.json | ||||
| !.vscode/tasks.json | ||||
| !.vscode/launch.json | ||||
| !.vscode/extensions.json | ||||
|  | ||||
| # idea | ||||
| .idea | ||||
|  | ||||
| # system | ||||
| Thumbs.db | ||||
| ehthumbs.db | ||||
| Desktop.ini | ||||
|  | ||||
| # temp files | ||||
| *.tmp | ||||
| *.temp | ||||
|  | ||||
| # local development | ||||
| *.local | ||||
|  | ||||
| public/r | ||||
|  | ||||
| .pnpm-store | ||||
							
								
								
									
										24
									
								
								.turbo/turbo-build.log
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.turbo/turbo-build.log
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
|  | ||||
| [33m[43m[30m WARN [39m[49m Issue while reading "/home/ubuntu/kevisual/center/submodules/query-login/.npmrc". Failed to replace env in config: ${ME_NPM_TOKEN} | ||||
| [43m[30m WARN [39m[49m Issue while reading "/home/ubuntu/kevisual/center/.npmrc". Failed to replace env in config: ${ME_NPM_TOKEN}[39m | ||||
|  | ||||
| > @kevisual/query-login@0.0.2 build /home/ubuntu/kevisual/center/submodules/query-login | ||||
| > tsup | ||||
|  | ||||
| [34mCLI[39m Building entry: src/query-login-browser.ts, src/query-login-node.ts, src/query-login.ts | ||||
| [34mCLI[39m Using tsconfig: tsconfig.json | ||||
| [34mCLI[39m tsup v8.4.0 | ||||
| [34mCLI[39m Using tsup config: /home/ubuntu/kevisual/center/submodules/query-login/tsup.config.ts | ||||
| [34mCLI[39m Target: esnext | ||||
| [34mCLI[39m Cleaning output folder | ||||
| [34mESM[39m Build start | ||||
| [33mESM[39m [33mYou have emitDecoratorMetadata enabled but @swc/core was not installed, skipping swc plugin[39m | ||||
| [32mESM[39m [1mdist/query-login-node.js    [22m[32m15.31 KB[39m | ||||
| [32mESM[39m [1mdist/query-login-browser.js [22m[32m11.80 KB[39m | ||||
| [32mESM[39m [1mdist/query-login.js         [22m[32m11.58 KB[39m | ||||
| [32mESM[39m ⚡️ Build success in 10ms | ||||
| DTS Build start | ||||
| DTS ⚡️ Build success in 873ms | ||||
| DTS dist/query-login-browser.d.ts 332.00 B | ||||
| DTS dist/query-login-node.d.ts    701.00 B | ||||
| DTS dist/query-login.d.ts         4.80 KB | ||||
							
								
								
									
										14
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,12 +1,14 @@ | ||||
| { | ||||
|   "name": "@kevisual/query-login", | ||||
|   "version": "0.0.2", | ||||
|   "version": "0.0.6", | ||||
|   "description": "", | ||||
|   "main": "dist/query-login.js", | ||||
|   "types": "dist/query-login.d.ts", | ||||
|   "scripts": { | ||||
|     "build": "tsup", | ||||
|     "watch": "tsup --watch" | ||||
|     "watch": "tsup --watch", | ||||
|     "dev": "tsup --watch", | ||||
|     "dev:lib": "pnpm run dev" | ||||
|   }, | ||||
|   "keywords": [], | ||||
|   "author": "abearxiong <xiongxiao@xiongxiao.me>", | ||||
| @@ -16,10 +18,10 @@ | ||||
|     "access": "public" | ||||
|   }, | ||||
|   "peerDependencies": { | ||||
|     "@kevisual/query": "^0.0.12" | ||||
|     "@kevisual/query": "^0.0.17" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/node": "^22.13.11", | ||||
|     "@types/node": "^22.14.1", | ||||
|     "tsup": "^8.4.0" | ||||
|   }, | ||||
|   "exports": { | ||||
| @@ -29,7 +31,7 @@ | ||||
|     "./browser": "./dist/query-login-browser.js" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@kevisual/cache": "^0.0.1", | ||||
|     "dotenv": "^16.4.7" | ||||
|     "@kevisual/cache": "^0.0.2", | ||||
|     "dotenv": "^16.5.0" | ||||
|   } | ||||
| } | ||||
| @@ -11,10 +11,23 @@ export interface Cache { | ||||
|    * @update 删除缓存 | ||||
|    */ | ||||
|   del(): Promise<void>; | ||||
|   /** | ||||
|    * 初始化 | ||||
|    */ | ||||
|   init?: () => Promise<any>; | ||||
| } | ||||
| type User = { | ||||
|   avatar?: string; | ||||
|   description?: string; | ||||
|   id?: string; | ||||
|   needChangePassword?: boolean; | ||||
|   orgs?: string[]; | ||||
|   type?: string; | ||||
|   username?: string; | ||||
| }; | ||||
|  | ||||
| export type CacheLoginUser = { | ||||
|   user?: any; | ||||
|   user?: User; | ||||
|   id?: string; | ||||
|   accessToken?: string; | ||||
|   refreshToken?: string; | ||||
| @@ -23,11 +36,15 @@ type CacheLogin = { | ||||
|   loginUsers: CacheLoginUser[]; | ||||
| } & CacheLoginUser; | ||||
|  | ||||
| export type CacheStore<T = any> = { | ||||
| export type CacheStore<T = Cache> = { | ||||
|   name: string; | ||||
|   /** | ||||
|    * 缓存数据 | ||||
|    * @important 需要先调用init | ||||
|    */ | ||||
|   cacheData: CacheLogin; | ||||
|   /** | ||||
|    * 实际操作的cache | ||||
|    * 实际操作的cache, 需要先调用init | ||||
|    */ | ||||
|   cache: T; | ||||
|  | ||||
| @@ -38,7 +55,7 @@ export type CacheStore<T = any> = { | ||||
|   /** | ||||
|    * 获取当前用户 | ||||
|    */ | ||||
|   getCurrentUser(): Promise<CacheLoginUser>; | ||||
|   getCurrentUser(): Promise<User>; | ||||
|   /** | ||||
|    * 获取当前用户列表 | ||||
|    */ | ||||
| @@ -51,10 +68,6 @@ export type CacheStore<T = any> = { | ||||
|    * 获取缓存的accessToken | ||||
|    */ | ||||
|   getAccessToken(): Promise<string>; | ||||
|   /** | ||||
|    * 初始化 | ||||
|    */ | ||||
|   init(): Promise<void>; | ||||
|   /** | ||||
|    * 清除当前用户 | ||||
|    */ | ||||
| @@ -63,9 +76,14 @@ export type CacheStore<T = any> = { | ||||
|    * 清除所有用户 | ||||
|    */ | ||||
|   clearAll(): Promise<void>; | ||||
| } & Cache; | ||||
|  | ||||
| type LoginCacheStoreOpts = { | ||||
|   getValue(): Promise<CacheLogin>; | ||||
|   setValue(value: CacheLogin): Promise<CacheLogin>; | ||||
|   delValue(): Promise<void>; | ||||
|   init(): Promise<any>; | ||||
| }; | ||||
|  | ||||
| export type LoginCacheStoreOpts = { | ||||
|   name: string; | ||||
|   cache: Cache; | ||||
| }; | ||||
| @@ -94,28 +112,41 @@ export class LoginCacheStore implements CacheStore<any> { | ||||
|    * @param value | ||||
|    * @returns | ||||
|    */ | ||||
|   async set(key: string, value: CacheLogin) { | ||||
|     await this.cache.set(key, value); | ||||
|   async setValue(value: CacheLogin) { | ||||
|     await this.cache.set(this.name, value); | ||||
|     this.cacheData = value; | ||||
|     return value; | ||||
|   } | ||||
|   /** | ||||
|    * 删除缓存 | ||||
|    */ | ||||
|   async del() { | ||||
|   async delValue() { | ||||
|     await this.cache.del(); | ||||
|   } | ||||
|   get(key: string): Promise<CacheLogin> { | ||||
|     return this.cache.get(key); | ||||
|   getValue(): Promise<CacheLogin> { | ||||
|     return this.cache.get(this.name); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 初始化,设置默认值 | ||||
|    */ | ||||
|   async init() { | ||||
|     this.cacheData = (await this.get(this.name)) || { | ||||
|     const defaultData = { | ||||
|       loginUsers: [], | ||||
|       user: null, | ||||
|       id: null, | ||||
|       accessToken: null, | ||||
|       refreshToken: null, | ||||
|     }; | ||||
|     if (this.cache.init) { | ||||
|       try { | ||||
|         const cacheData = await this.cache.init(); | ||||
|         this.cacheData = cacheData || defaultData; | ||||
|       } catch (error) { | ||||
|         console.log('cacheInit error', error); | ||||
|       } | ||||
|     } else { | ||||
|       this.cacheData = (await this.getValue()) || defaultData; | ||||
|     } | ||||
|   } | ||||
|   /** | ||||
|    * 设置当前用户 | ||||
| @@ -131,7 +162,7 @@ export class LoginCacheStore implements CacheStore<any> { | ||||
|     this.cacheData.id = user.id; | ||||
|     this.cacheData.accessToken = user.accessToken; | ||||
|     this.cacheData.refreshToken = user.refreshToken; | ||||
|     await this.set(this.name, this.cacheData); | ||||
|     await this.setValue(this.cacheData); | ||||
|   } | ||||
|  | ||||
|   getCurrentUser(): Promise<CacheLoginUser> { | ||||
| @@ -160,7 +191,7 @@ export class LoginCacheStore implements CacheStore<any> { | ||||
|     this.cacheData.id = undefined; | ||||
|     this.cacheData.accessToken = undefined; | ||||
|     this.cacheData.refreshToken = undefined; | ||||
|     await this.set(this.name, this.cacheData); | ||||
|     await this.setValue(this.cacheData); | ||||
|   } | ||||
|   async clearAll() { | ||||
|     this.cacheData.loginUsers = []; | ||||
| @@ -168,6 +199,6 @@ export class LoginCacheStore implements CacheStore<any> { | ||||
|     this.cacheData.id = undefined; | ||||
|     this.cacheData.accessToken = undefined; | ||||
|     this.cacheData.refreshToken = undefined; | ||||
|     await this.set(this.name, this.cacheData); | ||||
|     await this.setValue(this.cacheData); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,14 +1,21 @@ | ||||
| import { Cache } from './login-cache.ts'; | ||||
| import { homedir } from 'node:os'; | ||||
| import { join, dirname } from 'node:path'; | ||||
| import { readFileSync } from 'node:fs'; | ||||
| import { readFile, writeFile, unlink, stat, mkdir } from 'node:fs/promises'; | ||||
| export const fileExists = async (filePath: string, createIfNotExists = false) => { | ||||
| import fs from 'node:fs'; | ||||
| import { readFileSync, writeFileSync, accessSync } from 'node:fs'; | ||||
| import { readFile, writeFile, unlink, mkdir } from 'node:fs/promises'; | ||||
| export const fileExists = async ( | ||||
|   filePath: string, | ||||
|   { createIfNotExists = true, isFile = true, isDir = false }: { createIfNotExists?: boolean; isFile?: boolean; isDir?: boolean } = {}, | ||||
| ) => { | ||||
|   try { | ||||
|     await stat(filePath); | ||||
|     accessSync(filePath, fs.constants.F_OK); | ||||
|     return true; | ||||
|   } catch (error) { | ||||
|     if (createIfNotExists) { | ||||
|     if (createIfNotExists && isDir) { | ||||
|       await mkdir(filePath, { recursive: true }); | ||||
|       return true; | ||||
|     } else if (createIfNotExists && isFile) { | ||||
|       await mkdir(dirname(filePath), { recursive: true }); | ||||
|       return false; | ||||
|     } | ||||
| @@ -24,6 +31,9 @@ export const readConfigFile = (filePath: string) => { | ||||
|     return {}; | ||||
|   } | ||||
| }; | ||||
| export const writeConfigFile = (filePath: string, data: any) => { | ||||
|   writeFileSync(filePath, JSON.stringify(data, null, 2)); | ||||
| }; | ||||
| export const getHostName = () => { | ||||
|   const configDir = join(homedir(), '.config', 'envision'); | ||||
|   const configFile = join(configDir, 'config.json'); | ||||
| @@ -40,14 +50,13 @@ export class StorageNode implements Storage { | ||||
|     const configDir = join(homedir(), '.config', 'envision'); | ||||
|     const hostname = getHostName(); | ||||
|     this.filePath = join(configDir, 'config', `${hostname}-storage.json`); | ||||
|     fileExists(this.filePath, true); | ||||
|     fileExists(this.filePath, { isFile: true }); | ||||
|   } | ||||
|   async loadCache() { | ||||
|     const filePath = this.filePath; | ||||
|     try { | ||||
|       const data = await readFile(filePath, 'utf-8'); | ||||
|       const jsonData = JSON.parse(data); | ||||
|       this.cacheData = jsonData; | ||||
|       const data = await readConfigFile(filePath); | ||||
|       this.cacheData = data; | ||||
|     } catch (error) { | ||||
|       this.cacheData = {}; | ||||
|       await writeFile(filePath, JSON.stringify(this.cacheData, null, 2)); | ||||
| @@ -76,37 +85,48 @@ export class StorageNode implements Storage { | ||||
|   } | ||||
| } | ||||
| export class LoginNodeCache implements Cache { | ||||
|   name: string; | ||||
|   cacheData: any; | ||||
|   filePath: string; | ||||
|   constructor(name: string) { | ||||
|     this.name = name; | ||||
|     const hostname = getHostName(); | ||||
|     this.filePath = join(homedir(), '.config', 'envision', 'config', `${hostname}-${name}.json`); | ||||
|     fileExists(this.filePath, true); | ||||
|     this.loadCache(this.filePath); | ||||
|   } | ||||
|   filepath: string; | ||||
|  | ||||
|   constructor(filepath?: string) { | ||||
|     this.filepath = filepath || join(homedir(), '.config', 'envision', 'config', `${getHostName()}-login.json`); | ||||
|     fileExists(this.filepath, { isFile: true }); | ||||
|   } | ||||
|   async get(_key: string) { | ||||
|     try { | ||||
|       const filePath = this.filepath; | ||||
|       const data = readConfigFile(filePath); | ||||
|       return data; | ||||
|     } catch (error) { | ||||
|       console.log('get error', error); | ||||
|       return {}; | ||||
|     } | ||||
|   } | ||||
|   async set(_key: string, value: any) { | ||||
|     try { | ||||
|       const data = readConfigFile(this.filepath); | ||||
|       const newData = { ...data, ...value }; | ||||
|       writeConfigFile(this.filepath, newData); | ||||
|     } catch (error) { | ||||
|       console.log('set error', error); | ||||
|     } | ||||
|   } | ||||
|   async del() { | ||||
|     await unlink(this.filepath); | ||||
|   } | ||||
|   async loadCache(filePath: string) { | ||||
|     try { | ||||
|       const data = await readFile(filePath, 'utf-8'); | ||||
|       const jsonData = JSON.parse(data); | ||||
|       this.cacheData = jsonData; | ||||
|       return jsonData; | ||||
|     } catch (error) { | ||||
|       // console.log('loadCache error', error); | ||||
|       console.log('create new cache file:', filePath); | ||||
|       const defaultData = { loginUsers: [] }; | ||||
|       this.cacheData = defaultData; | ||||
|       await writeFile(filePath, JSON.stringify(defaultData, null, 2)); | ||||
|       writeConfigFile(filePath, defaultData); | ||||
|       return defaultData; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async get() { | ||||
|     return this.cacheData; | ||||
|   } | ||||
|   async set(key: string, value: any) { | ||||
|     this.cacheData = value; | ||||
|     await writeFile(this.filePath, JSON.stringify(this.cacheData, null, 2)); | ||||
|   } | ||||
|   async del() { | ||||
|     await unlink(this.filePath); | ||||
|   async init() { | ||||
|     return await this.loadCache(this.filepath); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ export class QueryLoginNode extends QueryLogin { | ||||
|     super({ | ||||
|       ...opts, | ||||
|       storage, | ||||
|       cache: new LoginNodeCache('login'), | ||||
|       cache: new LoginNodeCache(), | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { Query } from '@kevisual/query'; | ||||
| import { Query, BaseQuery } from '@kevisual/query'; | ||||
| import type { Result, DataOpts } from '@kevisual/query/query'; | ||||
| import { setBaseResponse } from '@kevisual/query/query'; | ||||
| import { LoginCacheStore, CacheStore } from './login-cache.ts'; | ||||
| @@ -21,20 +21,21 @@ export type QueryLoginResult = { | ||||
|   refreshToken: string; | ||||
| }; | ||||
|  | ||||
| export class QueryLogin { | ||||
|   query: Query; | ||||
| export class QueryLogin extends BaseQuery { | ||||
|   /** | ||||
|    * query login cache, 非实际操作, 一个cache的包裹模块 | ||||
|    */ | ||||
|   cache: CacheStore; | ||||
|   cacheStore: CacheStore; | ||||
|   isBrowser: boolean; | ||||
|   load?: boolean; | ||||
|   storage: Storage; | ||||
|   onLoad?: () => void; | ||||
|  | ||||
|   constructor(opts?: QueryLoginOpts) { | ||||
|     this.query = opts?.query || new Query(); | ||||
|     this.cache = new LoginCacheStore({ name: 'login', cache: opts.cache }); | ||||
|     super({ | ||||
|       query: opts?.query || new Query(), | ||||
|     }); | ||||
|     this.cacheStore = new LoginCacheStore({ name: 'login', cache: opts.cache }); | ||||
|     this.isBrowser = opts?.isBrowser ?? true; | ||||
|     this.init(); | ||||
|     this.onLoad = opts?.onLoad; | ||||
| @@ -44,12 +45,19 @@ export class QueryLogin { | ||||
|     this.query = query; | ||||
|   } | ||||
|   private async init() { | ||||
|     await this.cache.init(); | ||||
|     await this.cacheStore.init(); | ||||
|     this.load = true; | ||||
|     this.onLoad?.(); | ||||
|   } | ||||
|   async post<T = any>(data: any, opts?: DataOpts) { | ||||
|     return this.query.post<T>({ path: 'user', ...data }, opts); | ||||
|     try { | ||||
|       return this.query.post<T>({ path: 'user', ...data }, opts); | ||||
|     } catch (error) { | ||||
|       console.log('error', error); | ||||
|       return { | ||||
|         code: 400, | ||||
|       } as any; | ||||
|     } | ||||
|   } | ||||
|   /** | ||||
|    * 登录, | ||||
| @@ -79,6 +87,41 @@ export class QueryLogin { | ||||
|     } | ||||
|     return res; | ||||
|   } | ||||
|   /** | ||||
|    * 设置token | ||||
|    * @param token | ||||
|    */ | ||||
|   async setLoginToken(token: { accessToken: string; refreshToken: string }) { | ||||
|     const { accessToken, refreshToken } = token; | ||||
|     this.storage.setItem('token', accessToken || ''); | ||||
|     await this.beforeSetLoginUser({ accessToken, refreshToken }); | ||||
|   } | ||||
|   async loginByWechat(data: { code: string }) { | ||||
|     const res = await this.post<QueryLoginResult>({ path: 'wx', key: 'open-login', code: data.code }); | ||||
|     if (res.code === 200) { | ||||
|       const { accessToken, refreshToken } = res?.data || {}; | ||||
|       this.storage.setItem('token', accessToken || ''); | ||||
|       await this.beforeSetLoginUser({ accessToken, refreshToken }); | ||||
|     } | ||||
|     return res; | ||||
|   } | ||||
|   /** | ||||
|    * 检测微信登录,登陆成功后,调用onSuccess,否则调用onError | ||||
|    * @param param0 | ||||
|    */ | ||||
|   async checkWechat({ onSuccess, onError }: { onSuccess?: (res: QueryLoginResult) => void; onError?: (res: any) => void }) { | ||||
|     const url = new URL(window.location.href); | ||||
|     const code = url.searchParams.get('code'); | ||||
|     const state = url.searchParams.get('state'); | ||||
|     if (code && state) { | ||||
|       const res = await this.loginByWechat({ code }); | ||||
|       if (res.code === 200) { | ||||
|         onSuccess?.(res.data); | ||||
|       } else { | ||||
|         onError?.(res); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   /** | ||||
|    * 登陆成功,需要获取用户信息进行缓存 | ||||
|    * @param param0 | ||||
| @@ -89,7 +132,7 @@ export class QueryLogin { | ||||
|       if (resUser.code === 200) { | ||||
|         const user = resUser.data; | ||||
|         if (user) { | ||||
|           this.cache.setLoginUser({ | ||||
|           this.cacheStore.setLoginUser({ | ||||
|             user, | ||||
|             id: user.id, | ||||
|             accessToken, | ||||
| @@ -107,10 +150,10 @@ export class QueryLogin { | ||||
|    * @returns | ||||
|    */ | ||||
|   async queryRefreshToken(refreshToken?: string) { | ||||
|     const _refreshToken = refreshToken || this.cache.getRefreshToken(); | ||||
|     const _refreshToken = refreshToken || this.cacheStore.getRefreshToken(); | ||||
|     let data = { refreshToken: _refreshToken }; | ||||
|     if (!_refreshToken) { | ||||
|       await this.cache.clearCurrentUser(); | ||||
|       await this.cacheStore.clearCurrentUser(); | ||||
|       return { | ||||
|         code: 401, | ||||
|         message: '请先登录', | ||||
| @@ -129,6 +172,7 @@ export class QueryLogin { | ||||
|   } | ||||
|   /** | ||||
|    * 检查401错误,并刷新token, 如果refreshToken存在,则刷新token, 否则返回401 | ||||
|    * 拦截请求,请使用run401Action, 不要直接使用 afterCheck401ToRefreshToken | ||||
|    * @param response | ||||
|    * @param ctx | ||||
|    * @param refetch | ||||
| @@ -137,7 +181,7 @@ export class QueryLogin { | ||||
|   async afterCheck401ToRefreshToken(response: Result, ctx?: { req?: any; res?: any; fetch?: any }, refetch?: boolean) { | ||||
|     const that = this; | ||||
|     if (response?.code === 401) { | ||||
|       const hasRefreshToken = await that.cache.getRefreshToken(); | ||||
|       const hasRefreshToken = await that.cacheStore.getRefreshToken(); | ||||
|       if (hasRefreshToken) { | ||||
|         const res = await that.queryRefreshToken(hasRefreshToken); | ||||
|         if (res.code === 200) { | ||||
| @@ -159,13 +203,58 @@ export class QueryLogin { | ||||
|           } | ||||
|         } else { | ||||
|           that.storage.removeItem('token'); | ||||
|           await that.cache.clearCurrentUser(); | ||||
|           await that.cacheStore.clearCurrentUser(); | ||||
|         } | ||||
|         return res; | ||||
|       } | ||||
|     } | ||||
|     return response as any; | ||||
|   } | ||||
|   /** | ||||
|    * 一个简单的401处理, 如果401,则刷新token, 如果refreshToken不存在,则返回401 | ||||
|    * refetch 是否重新请求, 会有bug,无限循环,按需要使用 | ||||
|    * TODO: | ||||
|    * @param response | ||||
|    * @param ctx | ||||
|    * @param opts | ||||
|    * @returns | ||||
|    */ | ||||
|   async run401Action( | ||||
|     response: Result, | ||||
|     ctx?: { req?: any; res?: any; fetch?: any }, | ||||
|     opts?: { | ||||
|       /** | ||||
|        * 是否重新请求, 会有bug,无限循环,按需要使用 | ||||
|        */ | ||||
|       refetch?: boolean; | ||||
|       /** | ||||
|        * check之后的回调 | ||||
|        */ | ||||
|       afterCheck?: (res: Result) => any; | ||||
|       /** | ||||
|        * 401处理后, 还是401, 则回调 | ||||
|        */ | ||||
|       afterAlso401?: (res: Result) => any; | ||||
|     }, | ||||
|   ) { | ||||
|     const that = this; | ||||
|     const refetch = opts?.refetch ?? false; | ||||
|     if (response?.code === 401) { | ||||
|       if (that.query.stop === true) { | ||||
|         return { code: 500, success: false, message: 'refresh token loading...' }; | ||||
|       } | ||||
|       that.query.stop = true; | ||||
|       const res = await that.afterCheck401ToRefreshToken(response, ctx, refetch); | ||||
|       that.query.stop = false; | ||||
|       opts?.afterCheck?.(res); | ||||
|       if (res.code === 401) { | ||||
|         opts?.afterAlso401?.(res); | ||||
|       } | ||||
|       return res; | ||||
|     } else { | ||||
|       return response as any; | ||||
|     } | ||||
|   } | ||||
|   /** | ||||
|    * 获取用户信息 | ||||
|    * @param token | ||||
| @@ -181,10 +270,13 @@ export class QueryLogin { | ||||
|           if (config.headers) { | ||||
|             config.headers['Authorization'] = `Bearer ${_token}`; | ||||
|           } | ||||
|           if (!_token) { | ||||
|             // TODO: 取消请求,因为没有登陆 | ||||
|           } | ||||
|           return config; | ||||
|         }, | ||||
|         afterResponse: async (response, ctx) => { | ||||
|           if (response?.code === 401 && check401) { | ||||
|           if (response?.code === 401 && check401 && !token) { | ||||
|             return await that.afterCheck401ToRefreshToken(response, ctx); | ||||
|           } | ||||
|           return response as any; | ||||
| @@ -192,6 +284,25 @@ export class QueryLogin { | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
|   /** | ||||
|    * 检查本地用户,如果本地用户存在,则返回本地用户,否则返回null | ||||
|    * @returns | ||||
|    */ | ||||
|   async checkLocalUser() { | ||||
|     const user = await this.cacheStore.getCurrentUser(); | ||||
|     if (user) { | ||||
|       return user; | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
|   /** | ||||
|    * 检查本地token是否存在,简单的判断是否已经属于登陆状态 | ||||
|    * @returns | ||||
|    */ | ||||
|   async checkLocalToken() { | ||||
|     const token = this.storage.getItem('token'); | ||||
|     return !!token; | ||||
|   } | ||||
|   /** | ||||
|    * 请求更新,切换用户, 使用switchUser | ||||
|    * @param username | ||||
| @@ -206,7 +317,7 @@ export class QueryLogin { | ||||
|    * @returns | ||||
|    */ | ||||
|   async switchUser(username: string) { | ||||
|     const localUserList = await this.cache.getCurrentUserList(); | ||||
|     const localUserList = await this.cacheStore.getCurrentUserList(); | ||||
|     const user = localUserList.find((userItem) => userItem.user.username === username); | ||||
|     if (user) { | ||||
|       this.storage.setItem('token', user.accessToken || ''); | ||||
| @@ -230,11 +341,20 @@ export class QueryLogin { | ||||
|     } | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 退出登陆,去掉token, 并删除缓存 | ||||
|    * @returns | ||||
|    */ | ||||
|   async logout() { | ||||
|     this.storage.removeItem('token'); | ||||
|     this.cache.del(); | ||||
|     return this.post<Result>({ key: 'logout' }); | ||||
|     const users = await this.cacheStore.getCurrentUserList(); | ||||
|     const tokens = users | ||||
|       .map((user) => { | ||||
|         return user?.accessToken; | ||||
|       }) | ||||
|       .filter(Boolean); | ||||
|     this.cacheStore.delValue(); | ||||
|     return this.post<Result>({ key: 'logout', data: { tokens } }); | ||||
|   } | ||||
|   /** | ||||
|    * 检查用户名的组,这个用户是否存在 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user