midway-fatcms 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/libs/crud-pro/CrudPro.d.ts +14 -0
  2. package/dist/libs/crud-pro/CrudPro.js +61 -0
  3. package/dist/libs/crud-pro/interfaces.d.ts +20 -0
  4. package/dist/libs/crud-pro/models/ServiceHub.d.ts +2 -2
  5. package/dist/libs/crud-pro/models/Transaction.js +6 -1
  6. package/dist/libs/crud-pro/models/keys.d.ts +1 -0
  7. package/dist/libs/crud-pro/models/keys.js +2 -0
  8. package/dist/libs/crud-pro/services/CrudProDataFilterService.d.ts +17 -0
  9. package/dist/libs/crud-pro/services/CrudProDataFilterService.js +53 -0
  10. package/dist/libs/crud-pro/services/CrudProGenSqlCondition.d.ts +1 -0
  11. package/dist/libs/crud-pro/services/CrudProGenSqlCondition.js +30 -0
  12. package/dist/libs/crud-pro/services/CrudProOriginToExecuteSql.js +7 -1
  13. package/dist/libs/crud-pro/services/CrudProTableMetaService.d.ts +7 -4
  14. package/dist/libs/crud-pro/services/CrudProTableMetaService.js +127 -37
  15. package/dist/libs/crud-pro/services/CurdProServiceHub.d.ts +4 -2
  16. package/dist/libs/crud-pro/services/CurdProServiceHub.js +7 -2
  17. package/dist/libs/crud-pro/utils/MixinUtils.js +10 -9
  18. package/dist/middleware/forbidden.middleware.js +13 -2
  19. package/dist/middleware/global.middleware.js +1 -1
  20. package/dist/models/SystemEntities.d.ts +2 -1
  21. package/dist/models/SystemEntities.js +1 -0
  22. package/dist/service/AuthService.js +3 -0
  23. package/dist/service/base/BaseService.d.ts +1 -0
  24. package/dist/service/base/BaseService.js +4 -0
  25. package/dist/service/crudstd/CrudStdService.js +1 -1
  26. package/dist/service/proxyapi/ProxyApiService.js +22 -2
  27. package/dist/service/proxyapi/RouteHandler.d.ts +3 -2
  28. package/dist/service/proxyapi/RouteTrie.d.ts +1 -1
  29. package/dist/service/proxyapi/RouteTrie.js +1 -0
  30. package/dist/service/proxyapi/WeightedRoundRobin.d.ts +1 -1
  31. package/dist/service/proxyapi/WeightedRoundRobin.js +1 -0
  32. package/package.json +1 -1
  33. package/src/libs/crud-pro/CrudPro.ts +71 -0
  34. package/src/libs/crud-pro/interfaces.ts +22 -0
  35. package/src/libs/crud-pro/models/ServiceHub.ts +2 -2
  36. package/src/libs/crud-pro/models/Transaction.ts +5 -1
  37. package/src/libs/crud-pro/models/keys.ts +6 -2
  38. package/src/libs/crud-pro/services/CrudProDataFilterService.ts +58 -0
  39. package/src/libs/crud-pro/services/CrudProGenSqlCondition.ts +37 -0
  40. package/src/libs/crud-pro/services/CrudProOriginToExecuteSql.ts +10 -1
  41. package/src/libs/crud-pro/services/CrudProTableMetaService.ts +145 -40
  42. package/src/libs/crud-pro/services/CurdProServiceHub.ts +10 -3
  43. package/src/libs/crud-pro/utils/MixinUtils.ts +11 -10
  44. package/src/middleware/forbidden.middleware.ts +17 -7
  45. package/src/middleware/global.middleware.ts +1 -1
  46. package/src/models/SystemEntities.ts +1 -0
  47. package/src/service/AuthService.ts +3 -0
  48. package/src/service/base/BaseService.ts +5 -0
  49. package/src/service/crudstd/CrudStdService.ts +2 -1
  50. package/src/service/proxyapi/ProxyApiService.ts +22 -1
  51. package/src/service/proxyapi/RouteHandler.ts +4 -2
  52. package/src/service/proxyapi/RouteTrie.ts +1 -1
  53. package/src/service/proxyapi/WeightedRoundRobin.ts +2 -1
@@ -1,25 +1,24 @@
1
1
  import { CrudProServiceBase } from './CrudProServiceBase';
2
- import { SqlCfgModel } from '../models/SqlCfgModel';
3
- import { IExecuteUnsafeQueryCtx, ITableMeta } from '../interfaces';
2
+ import { IExecuteUnsafeQueryCtx, ITableColumn, ITableMeta, ITableMetaQuery } from '../interfaces';
4
3
  import { SqlDbType } from '../models/keys';
5
4
  // import { pickAndConvertRowsByMix } from '../utils/sqlConvert/convertMix';
6
5
 
7
6
  class CrudProTableMetaCache {
8
7
  private cacheMap: Record<string, ITableMeta> = {};
9
- private getCacheKey(sqlCfgModel: SqlCfgModel) {
10
- return `${sqlCfgModel.sqlDatabase}:::${sqlCfgModel.sqlSchema}:::${sqlCfgModel.sqlTable}`;
8
+ private getCacheKey(query: ITableMetaQuery) {
9
+ return `${query.sqlDatabase}:::${query.sqlSchema}:::${query.sqlDbType}:::${query.sqlTable}`;
11
10
  }
12
- public getMeta(sqlCfgModel: SqlCfgModel) {
13
- const cacheKey = this.getCacheKey(sqlCfgModel);
11
+ public getMeta(query: ITableMetaQuery) {
12
+ const cacheKey = this.getCacheKey(query);
14
13
  const obj = this.cacheMap[cacheKey];
15
- if (obj && obj.expiredTime < Date.now()) {
14
+ if (obj && obj.expiredTime > Date.now()) {
16
15
  return obj;
17
16
  }
18
17
  return null;
19
18
  }
20
19
 
21
- public setMeta(sqlCfgModel: SqlCfgModel, metaObj: ITableMeta) {
22
- const cacheKey = this.getCacheKey(sqlCfgModel);
20
+ public setMeta(query: ITableMetaQuery, metaObj: ITableMeta) {
21
+ const cacheKey = this.getCacheKey(query);
23
22
  this.cacheMap[cacheKey] = metaObj;
24
23
  }
25
24
  }
@@ -27,60 +26,166 @@ class CrudProTableMetaCache {
27
26
  const metaCache = new CrudProTableMetaCache();
28
27
 
29
28
  class CrudProTableMetaService extends CrudProServiceBase {
30
- async getTableMeta(sqlCfgModel: SqlCfgModel): Promise<ITableMeta> {
31
- let obj = metaCache.getMeta(sqlCfgModel);
29
+ public async getTableMeta(query: ITableMetaQuery): Promise<ITableMeta> {
30
+ let obj = metaCache.getMeta(query);
32
31
  if (!obj) {
33
- obj = await this.loadTableMeta(sqlCfgModel);
34
- metaCache.setMeta(sqlCfgModel, obj);
32
+ obj = await this.loadTableMeta(query);
33
+ metaCache.setMeta(query, obj);
35
34
  }
36
35
  return obj;
37
36
  }
38
37
 
39
- private async loadTableMeta(sqlCfgModel: SqlCfgModel): Promise<ITableMeta> {
38
+ private async loadTableMeta(query: ITableMetaQuery): Promise<ITableMeta> {
40
39
  const { tableMetaCacheTime } = this.getContextCfg();
41
40
 
42
- const obj = {
43
- expiredTime: Date.now() + tableMetaCacheTime || 1000 * 3600 * 24 * 365,
41
+ const obj: ITableMeta = {
42
+ expiredTime: Date.now() + (tableMetaCacheTime || 1000 * 3600 * 24 * 365),
44
43
  tableColumns: [],
44
+ columnDetails: [],
45
45
  };
46
46
 
47
47
  const baseInfo: IExecuteUnsafeQueryCtx = {
48
- sqlTable: sqlCfgModel.sqlTable,
49
- sqlDatabase: sqlCfgModel.sqlDatabase,
50
- sqlDbType: sqlCfgModel.sqlDbType,
48
+ sqlTable: query.sqlTable,
49
+ sqlDatabase: query.sqlDatabase,
50
+ sqlDbType: query.sqlDbType,
51
51
  };
52
52
 
53
- obj.tableColumns = await this.loadTableColumnInfo(baseInfo);
53
+ obj.columnDetails = await this.loadTableColumnDetails(baseInfo);
54
+ obj.tableColumns = obj.columnDetails.map(col => col.name);
54
55
 
55
56
  return obj;
56
57
  }
57
58
 
58
- private async loadTableColumnInfo(baseInfo: IExecuteUnsafeQueryCtx): Promise<string[]> {
59
+ private async loadTableColumnDetails(baseInfo: IExecuteUnsafeQueryCtx): Promise<ITableColumn[]> {
59
60
  if (baseInfo.sqlDbType === SqlDbType.mysql) {
60
- const queryRes = await this.executeUnsafeQuery(baseInfo, 'describe ' + baseInfo.sqlTable);
61
- const tableDescribe = queryRes.rows || []; //pickAndConvertRowsByMix(queryRes, baseInfo.sqlDbType);
62
- const tableDescribe2 = JSON.parse(JSON.stringify(tableDescribe));
63
- return tableDescribe2.map(fieldObj => {
64
- return fieldObj['Field'];
65
- });
61
+ return this.loadMySQLColumnDetails(baseInfo);
66
62
  } else if (baseInfo.sqlDbType === SqlDbType.postgres) {
67
- const schemaname = 'public';
68
- const columnArraySql = `
69
- SELECT
70
- *
71
- FROM information_schema.columns
72
- WHERE table_schema = '${schemaname}' and table_name = '${baseInfo.sqlTable}'
73
- ORDER BY ordinal_position;
74
- `.trim();
75
- const queryRes = await this.executeUnsafeQuery(baseInfo, columnArraySql);
76
- const tableDescribe = queryRes.rows || [];
77
- return tableDescribe.map(fieldObj => {
78
- return fieldObj['column_name'];
79
- });
63
+ return this.loadPostgreSQLColumnDetails(baseInfo);
64
+ } else if (baseInfo.sqlDbType === SqlDbType.sqlserver) {
65
+ return this.loadSQLServerColumnDetails(baseInfo);
80
66
  }
81
67
 
82
68
  throw new Error('暂不支持的数据库类型:' + baseInfo.sqlDbType);
83
69
  }
70
+
71
+ private async loadMySQLColumnDetails(baseInfo: IExecuteUnsafeQueryCtx): Promise<ITableColumn[]> {
72
+ const queryRes = await this.executeUnsafeQuery(baseInfo, 'DESCRIBE ' + baseInfo.sqlTable);
73
+ const tableDescribe = queryRes.rows || [];
74
+
75
+ return tableDescribe.map((fieldObj: any) => {
76
+ const { Field, Type, Null, Key, Default, Extra } = fieldObj;
77
+ return {
78
+ name: Field,
79
+ type: Type,
80
+ isNullable: Null === 'YES',
81
+ isPrimaryKey: Key === 'PRI',
82
+ defaultValue: Default,
83
+ comment: Extra,
84
+ };
85
+ });
86
+ }
87
+
88
+ private async loadPostgreSQLColumnDetails(baseInfo: IExecuteUnsafeQueryCtx): Promise<ITableColumn[]> {
89
+ const schemaname = baseInfo.sqlSchema || 'public';
90
+
91
+ // 获取列基本信息
92
+ const columnArraySql = `
93
+ SELECT
94
+ column_name,
95
+ data_type,
96
+ is_nullable,
97
+ column_default,
98
+ character_maximum_length
99
+ FROM information_schema.columns
100
+ WHERE table_schema = '${schemaname}' AND table_name = '${baseInfo.sqlTable}'
101
+ ORDER BY ordinal_position;
102
+ `.trim();
103
+
104
+ const queryRes = await this.executeUnsafeQuery(baseInfo, columnArraySql);
105
+ const columnArray = queryRes.rows || [];
106
+
107
+ // 获取字段注释
108
+ const commentMap = await this.loadPostgreSQLColumnComments(baseInfo, schemaname);
109
+
110
+ return columnArray.map((columnObj: any) => {
111
+ const { column_name, data_type, is_nullable, column_default, character_maximum_length } = columnObj;
112
+ return {
113
+ name: column_name,
114
+ type: data_type,
115
+ isNullable: is_nullable === 'YES',
116
+ defaultValue: column_default,
117
+ maxLength: character_maximum_length,
118
+ comment: commentMap[column_name],
119
+ };
120
+ });
121
+ }
122
+
123
+ private async loadPostgreSQLColumnComments(
124
+ baseInfo: IExecuteUnsafeQueryCtx,
125
+ schemaname: string
126
+ ): Promise<Record<string, string>> {
127
+ const commentArraySql = `
128
+ SELECT
129
+ a.attname AS column_name,
130
+ d.description AS column_comment
131
+ FROM pg_class c
132
+ JOIN pg_namespace n ON c.relnamespace = n.oid
133
+ JOIN pg_attribute a ON c.oid = a.attrelid
134
+ LEFT JOIN pg_description d ON c.oid = d.objoid AND a.attnum = d.objsubid
135
+ WHERE n.nspname = '${schemaname}'
136
+ AND c.relname = '${baseInfo.sqlTable}'
137
+ AND a.attnum > 0
138
+ ORDER BY a.attnum;
139
+ `.trim();
140
+
141
+ const queryRes = await this.executeUnsafeQuery(baseInfo, commentArraySql);
142
+ const commentArray = queryRes.rows || [];
143
+
144
+ const map: Record<string, string> = {};
145
+ commentArray.forEach((commentObj: any) => {
146
+ const { column_name, column_comment } = commentObj;
147
+ map[column_name] = column_comment || '';
148
+ });
149
+
150
+ return map;
151
+ }
152
+
153
+ private async loadSQLServerColumnDetails(baseInfo: IExecuteUnsafeQueryCtx): Promise<ITableColumn[]> {
154
+ const columnArraySql = `
155
+ SELECT
156
+ c.name AS column_name,
157
+ t.name AS data_type,
158
+ c.max_length,
159
+ c.precision,
160
+ c.scale,
161
+ c.is_nullable,
162
+ c.is_identity,
163
+ dc.definition AS column_default,
164
+ ep.value AS column_comment
165
+ FROM sys.columns c
166
+ JOIN sys.types t ON c.user_type_id = t.user_type_id
167
+ LEFT JOIN sys.default_constraints dc ON c.default_object_id = dc.object_id
168
+ LEFT JOIN sys.extended_properties ep ON c.object_id = ep.major_id AND c.column_id = ep.minor_id
169
+ WHERE c.object_id = OBJECT_ID('${baseInfo.sqlTable}')
170
+ ORDER BY c.column_id;
171
+ `.trim();
172
+
173
+ const queryRes = await this.executeUnsafeQuery(baseInfo, columnArraySql);
174
+ const columnArray = queryRes.rows || [];
175
+
176
+ return columnArray.map((columnObj: any) => {
177
+ const { column_name, data_type, is_nullable, column_default, column_comment, max_length, is_identity } = columnObj;
178
+ return {
179
+ name: column_name,
180
+ type: data_type,
181
+ isNullable: is_nullable,
182
+ defaultValue: column_default,
183
+ comment: column_comment,
184
+ maxLength: max_length,
185
+ isPrimaryKey: is_identity,
186
+ };
187
+ });
188
+ }
84
189
  }
85
190
 
86
191
  export { CrudProTableMetaService };
@@ -1,4 +1,4 @@
1
- import { IFuncCfgModel, IRequestCfgModel, ITableMeta } from '../interfaces';
1
+ import { IFuncCfgModel, IRequestCfgModel, ISqlCfgModel, ITableMeta, ITableMetaQuery } from '../interfaces';
2
2
  import { RequestModel } from '../models/RequestModel';
3
3
  import { CrudProFieldValidateService } from './CrudProFieldValidateService';
4
4
  import { CrudProFieldUpdateService } from './CrudProFieldUpdateService';
@@ -13,6 +13,7 @@ import { ICurdProServiceHub } from '../models/ServiceHub';
13
13
  import { FuncContext } from '../models/FuncContext';
14
14
  import { CrudProExecuteFuncService } from './CrudProExecuteFuncService';
15
15
  import { CrudProTableMetaService } from './CrudProTableMetaService';
16
+ import { CrudProDataFilterService } from './CrudProDataFilterService';
16
17
 
17
18
  class CurdProServiceHub implements ICurdProServiceHub {
18
19
  private readonly executeContext: ExecuteContext;
@@ -25,6 +26,7 @@ class CurdProServiceHub implements ICurdProServiceHub {
25
26
  private readonly originToExecuteSql: CrudProOriginToExecuteSql;
26
27
  private readonly executeFuncService: CrudProExecuteFuncService;
27
28
  private readonly tableMetaService: CrudProTableMetaService;
29
+ private readonly dataFilterService: CrudProDataFilterService;
28
30
 
29
31
  constructor(executeContext: ExecuteContext) {
30
32
  this.executeContext = executeContext;
@@ -36,6 +38,7 @@ class CurdProServiceHub implements ICurdProServiceHub {
36
38
  this.originToExecuteSql = new CrudProOriginToExecuteSql(this);
37
39
  this.executeFuncService = new CrudProExecuteFuncService(this);
38
40
  this.tableMetaService = new CrudProTableMetaService(this);
41
+ this.dataFilterService = new CrudProDataFilterService(this);
39
42
  }
40
43
 
41
44
  getExecuteContext(): ExecuteContext {
@@ -84,8 +87,12 @@ class CurdProServiceHub implements ICurdProServiceHub {
84
87
  return this.executeFuncService.executeFuncCfg(funCfg, funcContext);
85
88
  }
86
89
 
87
- async getTableMeta(sqlCfgModel: SqlCfgModel): Promise<ITableMeta> {
88
- return await this.tableMetaService.getTableMeta(sqlCfgModel);
90
+ async getTableMeta(query: ITableMetaQuery): Promise<ITableMeta> {
91
+ return await this.tableMetaService.getTableMeta(query);
92
+ }
93
+
94
+ async filterDataByTableMeta(data: Record<string, any>, sqlCfgModel: ISqlCfgModel | SqlCfgModel): Promise<Record<string, any>> {
95
+ return await this.dataFilterService.filterDataByTableMeta(data, sqlCfgModel);
89
96
  }
90
97
  }
91
98
 
@@ -201,9 +201,19 @@ const MixinUtils = {
201
201
  return;
202
202
  }
203
203
 
204
+ if (Array.isArray(obj)) {
205
+ const collection = obj;
206
+ for (let i = 0; i < collection.length; i++) {
207
+ const value = collection[i];
208
+ const curKeyPath = keyPath + '[' + i + ']';
209
+ objTravelCallback(value, null, i, curKeyPath);
210
+ MixinUtils.deepTravelObject(value, objTravelCallback, curKeyPath);
211
+ }
212
+ return;
213
+ }
214
+
204
215
  if (typeof obj === 'object') {
205
216
  const keys = Object.keys(obj);
206
-
207
217
  for (let i = 0; i < keys.length; i++) {
208
218
  const objKey = keys[i];
209
219
  const keyStr = objKey;
@@ -214,15 +224,6 @@ const MixinUtils = {
214
224
  }
215
225
  }
216
226
 
217
- if (Array.isArray(obj)) {
218
- const collection = obj;
219
- for (let i = 0; i < collection.length; i++) {
220
- const value = collection[i];
221
- const curKeyPath = keyPath + '[' + i + ']';
222
- objTravelCallback(value, null, i, curKeyPath);
223
- MixinUtils.deepTravelObject(value, objTravelCallback, curKeyPath);
224
- }
225
- }
226
227
  },
227
228
  removeEmptyAttrs(obj: any): any {
228
229
  const result = {};
@@ -8,7 +8,11 @@ const BLACK_EQUAL_LIST = [
8
8
  '/config.json',
9
9
  '/backend/.env',
10
10
  '/.env',
11
+ '/.env.dev',
12
+ '/.env.prod',
11
13
  '/.env.local',
14
+ '/.env.staging',
15
+ '/.env.example',
12
16
  '/.env.production',
13
17
  '/.env.development',
14
18
  '/application.yml',
@@ -18,6 +22,7 @@ const BLACK_EQUAL_LIST = [
18
22
  '/config.yml',
19
23
  '/db.ini',
20
24
  '/database.yml',
25
+ '/api/.env',
21
26
  // 安全相关文件
22
27
  '/.well-known/security.txt',
23
28
  '/security.txt',
@@ -163,7 +168,7 @@ const SUSPICIOUS_USER_AGENTS = [
163
168
 
164
169
  /**
165
170
  * 安全防护中间件 - 黑名单路径拦截
166
- *
171
+ *
167
172
  * 核心职责:
168
173
  * 1. 防御恶意爬虫:拦截常见的配置文件探测请求(.env、config.json等)
169
174
  * 2. 防御漏洞扫描:阻止安全扫描工具对敏感目录的探测(.git、.aws等)
@@ -171,13 +176,13 @@ const SUSPICIOUS_USER_AGENTS = [
171
176
  * 4. 防御路径遍历:检测并阻止 ../ 等路径遍历攻击尝试
172
177
  * 5. 识别攻击工具:检测User-Agent中的sqlmap、nikto等渗透测试工具
173
178
  * 6. 性能优化:提前拦截无效请求,避免进入业务逻辑层消耗资源
174
- *
179
+ *
175
180
  * 应用场景:
176
181
  * - 公网暴露的Web应用:防止自动化工具批量扫描敏感路径
177
182
  * - 云原生部署环境:保护云服务配置文件不被探测(.aws、.env等)
178
183
  * - 多技术栈迁移:新系统可能残留旧技术栈痕迹,统一拦截避免误暴露
179
184
  * - 安全合规要求:主动防御已知的常见攻击路径,降低安全风险
180
- *
185
+ *
181
186
  * 拦截策略:
182
187
  * - User-Agent检测:识别常见扫描工具(sqlmap, nikto, nmap, metasploit等)
183
188
  * - 路径遍历检测:阻止 ../, ..\, %2e%2e%2f 等编码后的遍历尝试
@@ -185,13 +190,13 @@ const SUSPICIOUS_USER_AGENTS = [
185
190
  * - 前缀匹配:.git/、.svn/、.aws/等版本控制和云服务目录
186
191
  * - 模糊匹配:wp-admin、wp-content等WordPress相关路径
187
192
  * - 后缀匹配:.php/.jsp/.asp等脚本文件、.bak/.sql等敏感文件
188
- *
193
+ *
189
194
  * 防御能力增强:
190
195
  * - 支持30+种敏感配置文件拦截
191
196
  * - 支持50+种敏感目录前缀拦截
192
197
  * - 支持40+种危险文件后缀拦截
193
198
  * - 支持10+种常见攻击工具识别
194
- *
199
+ *
195
200
  * 注意事项:
196
201
  * 此中间件拦截的路径在实际项目中并不存在,仅为安全防护层。
197
202
  * 被拦截的请求会立即返回404,不会进入后续业务逻辑。
@@ -288,8 +293,13 @@ export class ForbiddenMiddleware implements IMiddleware<Context, NextFunction> {
288
293
  * 检查是否包含路径遍历政击特征
289
294
  */
290
295
  private hasPathTraversal(path: string): boolean {
291
- const decodedPath = decodeURIComponent(path);
292
- return SUSPICIOUS_QUERY_PATTERNS.some(pattern => decodedPath.includes(pattern));
296
+ try {
297
+ const decodedPath = decodeURIComponent(path);
298
+ return SUSPICIOUS_QUERY_PATTERNS.some(pattern => decodedPath.includes(pattern));
299
+ } catch (e) {
300
+ // URL解码失败(如包含非法编码字符),直接判定为可疑请求
301
+ return true;
302
+ }
293
303
  }
294
304
 
295
305
  /**
@@ -77,7 +77,7 @@ function handleNullRes(res: any): ICommonResult {
77
77
  * @param res
78
78
  */
79
79
  function handleArrayRes(res: any): ICommonResult {
80
- if (Array.isArray(res) && res.length) {
80
+ if (Array.isArray(res)) {
81
81
  return { success: true, data: res };
82
82
  }
83
83
  return res;
@@ -79,6 +79,7 @@ export enum ProxyUserContextEnum {
79
79
  NO_PASS = 0,
80
80
  BASIC_INFO = 1,
81
81
  SESSION_INFO = 2,
82
+ BASIC_INFO_BIZ_EXT = 3,
82
83
  }
83
84
 
84
85
  export interface IProxyApiEntity extends IApiBaseEntity {
@@ -178,6 +178,9 @@ export class AuthService extends BaseService {
178
178
  if (!isEnableSuperAdmin(this.ctx)) {
179
179
  return null;
180
180
  }
181
+ if(!Array.isArray(superAdminList)) {
182
+ return null;
183
+ }
181
184
  return superAdminList.find((s)=>{
182
185
  return s.login_name === loginName;
183
186
  })
@@ -112,6 +112,11 @@ export class BaseService {
112
112
  this.getContextLogger().debug(msg, ...args);
113
113
  }
114
114
 
115
+ protected isProdEnv(): boolean {
116
+ const env = this.ctx.app.env;
117
+ return env === 'prod' || env === 'production';
118
+ }
119
+
115
120
  protected isLocalEnv(): boolean {
116
121
  return isLocalEnv(this.ctx);
117
122
  }
@@ -95,11 +95,12 @@ export class CrudStdService extends ApiBaseService {
95
95
  public async executeStdQuery(stdAction: ICrudStdActionParams, params: IRequestModelCrudProExt, sqlSimpleName: KeysOfSimpleSQL): Promise<ExecuteContext> {
96
96
  const appCode = stdAction.appCode;
97
97
  const appInfo = await this.getParsedCrudStdAppForSettingKey(stdAction);
98
- const stdCrudCfgObj = appInfo.stdCrudCfgObj;
99
98
 
100
99
  if (!appInfo || appInfo.status !== 1) {
101
100
  throw new BizException('应用不存在或已下线:' + appCode);
102
101
  }
102
+
103
+ const stdCrudCfgObj = appInfo.stdCrudCfgObj;
103
104
 
104
105
  //删除策略
105
106
  const deleteStrategy = _.get(stdCrudCfgObj, 'othersSetting.values.deleteStrategy');
@@ -46,7 +46,8 @@ export class ProxyApiService extends ApiBaseService {
46
46
  if (!cfgInfo) {
47
47
  throw new BizException('路径配置没有匹配到', Exceptions.CFG_NOT_FOUND);
48
48
  }
49
- return this._handleProxyRequestForCfg(cfgInfo, upstream_path);
49
+ const proxyApiEntity: IProxyApiEntity = JSON.parse(JSON.stringify(cfgInfo));
50
+ return this._handleProxyRequestForCfg(proxyApiEntity, upstream_path);
50
51
  }
51
52
 
52
53
  /**
@@ -286,6 +287,7 @@ export class ProxyApiService extends ApiBaseService {
286
287
  const workbenchCode = this.ctx.workbenchInfo?.workbench_code;
287
288
  const userBasicInfo: any = { isLogin };
288
289
  if (sessionInfo && isLogin) {
290
+ userBasicInfo.nickName = sessionInfo.nickName;
289
291
  userBasicInfo.loginName = sessionInfo.loginName;
290
292
  userBasicInfo.sessionId = sessionInfo.sessionId;
291
293
  userBasicInfo.accountId = sessionInfo.accountId;
@@ -296,6 +298,25 @@ export class ProxyApiService extends ApiBaseService {
296
298
  return toBase64(userBasicInfo);
297
299
  }
298
300
 
301
+ // 传递用户基本信息和BizExt
302
+ if (proxyApiEntity.user_context === ProxyUserContextEnum.BASIC_INFO_BIZ_EXT) {
303
+ const isLogin = this.ctx.userSession.isLogin();
304
+ const sessionInfo = this.ctx.userSession.getSessionInfo();
305
+ const workbenchCode = this.ctx.workbenchInfo?.workbench_code;
306
+ const userBasicInfo: any = { isLogin };
307
+ if (sessionInfo && isLogin) {
308
+ userBasicInfo.nickName = sessionInfo.nickName;
309
+ userBasicInfo.loginName = sessionInfo.loginName;
310
+ userBasicInfo.sessionId = sessionInfo.sessionId;
311
+ userBasicInfo.accountId = sessionInfo.accountId;
312
+ userBasicInfo.workbenchCode = sessionInfo.workbenchCode;
313
+ userBasicInfo.accountType = sessionInfo.accountType;
314
+ userBasicInfo.bizExt = sessionInfo.bizExt; // 多了一个bizExt
315
+ }
316
+ userBasicInfo.workbenchCode = workbenchCode;
317
+ return toBase64(userBasicInfo);
318
+ }
319
+
299
320
  return null;
300
321
  }
301
322
  }
@@ -1,6 +1,8 @@
1
+ import {IProxyApiEntity} from "@/models/SystemEntities";
2
+
1
3
  class RouteHandler {
2
- cfgInfo: any;
3
- constructor(cfgInfo: any) {
4
+ cfgInfo: IProxyApiEntity;
5
+ constructor(cfgInfo: IProxyApiEntity) {
4
6
  this.cfgInfo = cfgInfo;
5
7
  }
6
8
  }
@@ -13,7 +13,7 @@ class RouteTrieNode {
13
13
 
14
14
  class RouteTrie {
15
15
  private root: RouteTrieNode;
16
- private routeCount: 0;
16
+ private routeCount: number = 0;
17
17
  constructor() {
18
18
  this.root = new RouteTrieNode();
19
19
  this.routeCount = 0;
@@ -7,7 +7,7 @@ interface IUpstreamItemExt extends IUpstreamItem {
7
7
 
8
8
  class WeightedRoundRobin {
9
9
  private readonly totalWeight: number;
10
- private servers: IUpstreamItemExt[];
10
+ private readonly servers: IUpstreamItemExt[];
11
11
  constructor(servers: IUpstreamItem[]) {
12
12
  this.servers = servers.map(server => ({
13
13
  ...server,
@@ -34,6 +34,7 @@ class WeightedRoundRobin {
34
34
  // 2. 被选中的服务器减去总权重(实现平滑分配)
35
35
  if (selected) {
36
36
  selected.currentWeight -= this.totalWeight;
37
+ selected.currentWeight = Math.max(selected.currentWeight, 0);
37
38
  return selected;
38
39
  }
39
40