using System.Data; using System.Diagnostics; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Web; using JNPF.ClayObject; using JNPF.Common.Configuration; using JNPF.Common.Const; using JNPF.Common.Core.Manager; using JNPF.Common.Core.Manager.Files; using JNPF.Common.Dtos.OAuth; using JNPF.Common.Dtos.VisualDev; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Filter; using JNPF.Common.Manager; using JNPF.Common.Models; using JNPF.Common.Net; using JNPF.Common.Security; using JNPF.DatabaseAccessor; using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.Extras.Thirdparty.JSEngine; using JNPF.FriendlyException; using JNPF.LinqBuilder; using JNPF.Logging.Attributes; using JNPF.RemoteRequest.Extensions; using JNPF.SensitiveDetection; using JNPF.Systems.Entitys.Dto.DataInterFace; using JNPF.Systems.Entitys.Dto.System.DataInterFace; using JNPF.Systems.Entitys.Model.DataInterFace; using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.System; using JNPF.UnifyResult; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; using SqlSugar; namespace JNPF.Systems; /// /// 数据接口 /// 版 本:V3.2 /// 版 权:引迈信息技术有限公司(https://www.jnpfsoft.com) /// 作 者:JNPF开发平台组 /// 日 期:2021-06-01. /// [ApiDescriptionSettings(Tag = "System", Name = "DataInterface", Order = 204)] [Route("api/system/[controller]")] public class DataInterfaceService : IDataInterfaceService, IDynamicApiController, ITransient { /// /// 服务基础仓储. /// private readonly ISqlSugarRepository _repository; /// /// 数据字典服务. /// private readonly IDictionaryDataService _dictionaryDataService; /// /// 脱敏词汇提供器. /// private readonly ISensitiveDetectionProvider _sensitiveDetectionProvider; /// /// 数据库管理. /// private readonly IDataBaseManager _dataBaseManager; /// /// 用户管理. /// private readonly IUserManager _userManager; /// /// 缓存管理. /// private readonly ICacheManager _cacheManager; /// /// 文件服务. /// private readonly IFileManager _fileManager; /// /// 初始化 SqlSugar 客户端. /// private readonly SqlSugarScope _sqlSugarClient; /// /// 数据库上下文ID. /// private string _configId = App.Configuration["ConnectionStrings:ConfigId"]; /// /// 数据库名称. /// private string _dbName = App.Configuration["ConnectionStrings:DBName"]; /// /// 初始化一个类型的新实例. /// public DataInterfaceService( ISqlSugarRepository repository, IDictionaryDataService dictionaryDataService, IDataBaseManager dataBaseManager, IUserManager userManager, ICacheManager cacheManager, IFileManager fileManager, ISensitiveDetectionProvider sensitiveDetectionProvider, ISqlSugarClient context) { _sensitiveDetectionProvider = sensitiveDetectionProvider; _repository = repository; _dictionaryDataService = dictionaryDataService; _fileManager = fileManager; _dataBaseManager = dataBaseManager; _cacheManager = cacheManager; _userManager = userManager; _sqlSugarClient = (SqlSugarScope)context; } #region Get /// /// 获取接口列表(分页). /// /// 参数. /// [HttpGet("")] public async Task GetList([FromQuery] DataInterfaceListQuery input) { var list = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.CreatorUserId)) .Where(a => a.DeleteMark == null) .WhereIF(!string.IsNullOrEmpty(input.categoryId), a => a.CategoryId == input.categoryId) .WhereIF(!string.IsNullOrEmpty(input.keyword), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)) .OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc) .Select((a, b) => new DataInterfaceListOutput { id = a.Id, categoryId = a.CategoryId, creatorTime = a.CreatorTime, creatorUser = SqlFunc.MergeString(b.RealName, "/", b.Account), dataType = a.DataType, dbLinkId = a.DBLinkId, description = a.Description, enCode = a.EnCode, fullName = a.FullName, enabledMark = a.EnabledMark, path = a.Path, query = a.Query, requestMethod = SqlFunc.IF(a.RequestMethod.Equals("1")).Return("新增").ElseIF(a.RequestMethod.Equals("2")).Return("修改") .ElseIF(a.RequestMethod.Equals("3")).Return("查询").ElseIF(a.RequestMethod.Equals("4")).Return("删除") .ElseIF(a.RequestMethod.Equals("5")).Return("存储过程").ElseIF(a.RequestMethod.Equals("6")).Return("Get") .End("Post"), requestParameters = a.RequestParameters, responseType = a.ResponseType, sortCode = a.SortCode, checkType = a.CheckType, tenantId = _userManager.TenantId }).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(list); } /// /// 获取接口列表(分页). /// /// 参数. /// [HttpGet("getList")] public async Task getList([FromQuery] DataInterfaceListQuery input) { var list = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.CreatorUserId)) .Where(a => a.DeleteMark == null) .WhereIF(!string.IsNullOrEmpty(input.categoryId), a => a.CategoryId == input.categoryId) .WhereIF(!string.IsNullOrEmpty(input.dataType), a => a.DataType.ToString() == input.dataType) .WhereIF(!string.IsNullOrEmpty(input.keyword), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)) .OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc) .Select((a, b) => new DateInterfaceGetListOutput { id = a.Id, categoryId = a.CategoryId, creatorTime = a.CreatorTime, creatorUser = SqlFunc.MergeString(b.RealName, "/", b.Account), _dataType = a.DataType, dbLinkId = a.DBLinkId, description = a.Description, enCode = a.EnCode, fullName = a.FullName, enabledMark = a.EnabledMark, path = a.Path, query = a.Query, requestMethod = SqlFunc.IF(a.RequestMethod.Equals("1")).Return("新增").ElseIF(a.RequestMethod.Equals("2")).Return("修改") .ElseIF(a.RequestMethod.Equals("3")).Return("查询").ElseIF(a.RequestMethod.Equals("4")).Return("删除") .ElseIF(a.RequestMethod.Equals("5")).Return("存储过程").ElseIF(a.RequestMethod.Equals("6")).Return("Get") .End("Post"), requestParameters = a.RequestParameters, responseType = a.ResponseType, sortCode = a.SortCode, checkType = a.CheckType, tenantId = _userManager.TenantId }).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(list); } /// /// 获取接口列表下拉框. /// /// [HttpGet("Selector")] public async Task GetSelector() { List tree = new List(); foreach (var entity in await _repository.AsQueryable().Where(x => x.DeleteMark == null && x.EnabledMark == 1).OrderBy(x => x.SortCode).ToListAsync()) { var dictionaryDataEntity = await _dictionaryDataService.GetInfo(entity.CategoryId); if (dictionaryDataEntity != null && tree.Where(t => t.id == entity.CategoryId).Count() == 0) { DataInterfaceSelectorOutput firstModel = dictionaryDataEntity.Adapt(); firstModel.categoryId = "0"; DataInterfaceSelectorOutput treeModel = entity.Adapt(); treeModel.categoryId = "1"; treeModel.parentId = dictionaryDataEntity.Id; firstModel.children.Add(treeModel); tree.Add(firstModel); } else { DataInterfaceSelectorOutput treeModel = entity.Adapt(); treeModel.categoryId = "1"; treeModel.parentId = entity.CategoryId; var parent = tree.Where(t => t.id == entity.CategoryId).FirstOrDefault(); if (parent != null) { parent.children.Add(treeModel); } } } return tree.OrderBy(x => x.sortCode).ToList(); } /// /// 获取接口数据. /// /// [HttpGet("{id}")] public async Task GetInfo_Api(string id) { return (await GetInfo(id)).Adapt(); } /// /// 获取预览参数. /// /// /// [HttpGet("GetParam/{id}")] [UnitOfWork] public async Task GetParam(string id) { var info = await GetInfo(id); if (info.IsNotEmptyOrNull() && info.RequestParameters.IsNotEmptyOrNull()) { return info.RequestParameters.ToList(); } else { return new List(); } } /// /// 访问接口 选中 回写. /// /// [AllowAnonymous] [IgnoreLog] [HttpGet("{id}/Action/Info")] public async Task ActionsResponseInfo(string id, [FromQuery] string tenantId, [FromQuery] VisualDevDataFieldDataListInput input) { return await GetResponseByType(id, 1, tenantId, input); } /// /// 导出. /// /// /// [HttpGet("{id}/Action/Export")] public async Task ActionsExport(string id) { var data = await GetInfo(id); var jsonStr = data.ToJsonString(); return await _fileManager.Export(jsonStr, data.FullName, ExportFileType.bd); } #endregion #region Post /// /// 预览接口. /// /// /// [HttpPost("{id}/Actions/Preview")] [UnitOfWork] public async Task Preview(string id, [FromBody] DataInterfacePreviewInput input) { _configId = _userManager.TenantId; _dbName = _userManager.TenantDbName; object output = null; var info = await GetInfo(id); var dicParameters = new Dictionary(); if (input.paramList.IsNotEmptyOrNull() && input.paramList.Count > 0) { dicParameters = input.paramList.ToDictionary(x => x.field, y => y.defaultValue); } VerifyRequired(info, dicParameters); ReplaceParameterValue(info, dicParameters); if (info?.DataType == 1) { output = await GetData(info); } else if (info?.DataType == 2) { output = info.Query.ToObject(); } else { output = await GetApiDataByTypePreview(info); } if (info is null || info.DataProcessing.IsNullOrEmpty()) { return output; } else { string sheetData = Regex.Match(info.DataProcessing, @"\{(.*)\}", RegexOptions.Singleline).Groups[1].Value; var scriptStr = "var result = function(data){data = JSON.parse(data);" + sheetData + "}"; return JsEngineUtil.CallFunction(scriptStr, output.ToJsonString(CommonConst.options));//此处时间非时间戳 } } /// /// 访问接口 选中 回写. /// /// [AllowAnonymous] [IgnoreLog] [HttpPost("{id}/Action/InfoByIds")] public async Task ActionsResponseInfoNew(string id, [FromBody] VisualDevDataFieldDataListInput input) { return await GetResponseByType(id, 1, string.Empty, input); } /// /// 访问接口 分页. /// /// [AllowAnonymous] [IgnoreLog] [HttpPost("{id}/Action/List")] public async Task ActionsResponseList(string id, [FromBody] VisualDevDataFieldDataListInput input) { return await GetResponseByType(id, 0, string.Empty, input); } /// /// 外部访问接口. /// /// /// 有值则为地址请求,没有则是内部请求. /// [AllowAnonymous] [IgnoreLog] [HttpPost("{id}/Actions/Response")] [UnitOfWork] public async Task ActionsResponse(string id, [FromQuery] string tenantId, [FromBody] Dictionary dic) { return await InterfaceVerify(id, tenantId, dic); } /// /// 添加接口. /// /// 参数. /// [HttpPost("")] public async Task Create([FromBody] DataInterfaceCrInput input) { var entity = input.Adapt(); var isOk = await _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); if (isOk < 1) throw Oops.Oh(ErrorCode.COM1000); } /// /// 修改接口. /// /// 主键id. /// 参数. /// [HttpPut("{id}")] public async Task Update(string id, [FromBody] DataInterfaceUpInput input) { var entity = input.Adapt(); var isOk = await _repository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync(); if (!isOk) throw Oops.Oh(ErrorCode.COM1001); } /// /// 删除接口. /// /// 主键id. /// [HttpDelete("{id}")] public async Task Delete_Api(string id) { var isOk = await _repository.AsUpdateable().SetColumns(it => new DataInterfaceEntity() { DeleteMark = 1, DeleteTime = DateTime.Now, DeleteUserId = _userManager.UserId }).Where(it => it.Id == id).ExecuteCommandHasChangeAsync(); if (!isOk) throw Oops.Oh(ErrorCode.COM1002); } /// /// 更新接口状态. /// /// 主键id. /// [HttpPut("{id}/Actions/State")] public async Task UpdateState(string id) { var isOk = await _repository.AsUpdateable().SetColumns(it => new DataInterfaceEntity() { EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1), LastModifyTime = DateTime.Now, LastModifyUserId = _userManager.UserId }).Where(it => it.Id == id).ExecuteCommandHasChangeAsync(); if (!isOk) throw Oops.Oh(ErrorCode.COM1003); } /// /// 导入. /// /// /// [HttpPost("Action/Import")] public async Task ActionsImport(IFormFile file) { var fileType = Path.GetExtension(file.FileName).Replace(".", string.Empty); if (!fileType.ToLower().Equals(ExportFileType.bd.ToString())) throw Oops.Oh(ErrorCode.D3006); var josn = _fileManager.Import(file); var data = josn.ToObject(); if (data == null) throw Oops.Oh(ErrorCode.D3006); var isOk = await _repository.AsSugarClient().Storageable(data).ExecuteCommandAsync(); if (isOk < 1) throw Oops.Oh(ErrorCode.D3008); } /// /// 外部接口授权码. /// /// /// /// /// [AllowAnonymous] [IgnoreLog] [HttpPost("Actions/GetAuth")] public async Task GetAuthorization([FromQuery] string appId, [FromQuery] string tenantId, [FromQuery] string intefaceId, [FromBody] Dictionary dic) { if (KeyVariable.MultiTenancy) { tenantId = tenantId.IsNullOrEmpty() ? _userManager.TenantId : tenantId; var interFace = App.Configuration["Tenant:MultiTenancyDBInterFace"] + tenantId; var response = await interFace.GetAsStringAsync(); var result = response.ToObject>(); if (result.code != 200) throw Oops.Oh(result.msg); else if (result.data.dotnet == null) throw Oops.Oh(ErrorCode.D1025); if (!_sqlSugarClient.IsAnyConnection(tenantId)) { _sqlSugarClient.AddConnection(new ConnectionConfig() { DbType = (SqlSugar.DbType)Enum.Parse(typeof(SqlSugar.DbType), App.Configuration["ConnectionStrings:DBType"]), ConfigId = tenantId, // 设置库的唯一标识 IsAutoCloseConnection = true, ConnectionString = string.Format($"{App.Configuration["ConnectionStrings:DefaultConnection"]}", result.data.dotnet) }); } _sqlSugarClient.ChangeDatabase(tenantId); } var interfaceOauthEntity = await _sqlSugarClient.Queryable().FirstAsync(x => x.AppId == appId && x.DeleteMark == null && x.EnabledMark == 1); if (interfaceOauthEntity == null) return null; var ymDate = DateTime.Now.ParseToUnixTime().ToString(); var authorization = GetVerifySignature(interfaceOauthEntity, intefaceId, ymDate); return new { YmDate = ymDate, Authorization = authorization, }; } #endregion #region PublicMethod /// /// 信息. /// /// 主键id. /// [NonAction] public async Task GetInfo(string id) { return await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); } /// /// 查询. /// /// /// [NonAction] public async Task GetData(DataInterfaceEntity entity) { return await connection(entity.DBLinkId, entity.Query, entity.RequestMethod); } /// /// 根据不同类型请求接口. /// /// /// 0 : 分页 1 :详情 ,其他 原始. /// /// /// [NonAction] public async Task GetResponseByType(string id, int type, string tenantId, VisualDevDataFieldDataListInput input = null, Dictionary dicParameters = null) { try { if (KeyVariable.MultiTenancy) { tenantId = tenantId.IsNullOrEmpty() ? _userManager.TenantId : tenantId; var interFace = App.Configuration["Tenant:MultiTenancyDBInterFace"] + tenantId; var response = await interFace.GetAsStringAsync(); var result = response.ToObject>(); if (result.code != 200) throw Oops.Oh(result.msg); else if (result.data.dotnet == null) throw Oops.Oh(ErrorCode.D1025); if (!_sqlSugarClient.IsAnyConnection(tenantId)) { _sqlSugarClient.AddConnection(new ConnectionConfig() { DbType = (SqlSugar.DbType)Enum.Parse(typeof(SqlSugar.DbType), App.Configuration["ConnectionStrings:DBType"]), ConfigId = tenantId, // 设置库的唯一标识 IsAutoCloseConnection = true, ConnectionString = string.Format($"{App.Configuration["ConnectionStrings:DefaultConnection"]}", result.data.dotnet) }); } _sqlSugarClient.ChangeDatabase(tenantId); _configId = tenantId; _dbName = result.data.dotnet; } var data = await _sqlSugarClient.Queryable().FirstAsync(x => x.Id == id && x.DeleteMark == null); if (data == null) throw Oops.Oh(ErrorCode.COM1005); // 远端数据(sql过滤) if (input.IsNotEmptyOrNull()) { var columnList = new List(); if (input.keyword.IsNotEmptyOrNull()) input.columnOptions.Split(",").ToList().ForEach(x => columnList.Add(string.Format("{0} like '%{1}%'", x, input.keyword))); if (columnList.Any() && !string.IsNullOrWhiteSpace(input.keyword)) data.Query = string.Format("select * from ({0}) t where {1} ", data.Query.TrimEnd(';'), string.Join(" or ", columnList)); else if (!string.IsNullOrWhiteSpace(input.relationField) && !string.IsNullOrWhiteSpace(input.keyword)) data.Query = string.Format("select * from ({0}) t where {1} like '%{2}%' ", data.Query.TrimEnd(';'), input.relationField, input.keyword); if (!string.IsNullOrWhiteSpace(input.propsValue) && !string.IsNullOrWhiteSpace(input.id)) data.Query = string.Format("select * from ({0}) t where {1} = '{2}' ", data.Query.TrimEnd(';'), input.propsValue, input.id); if (!string.IsNullOrWhiteSpace(input.propsValue) && input.ids.Any()) data.Query = string.Format("select * from ({0}) t where {1} in ('{2}') ", data.Query.TrimEnd(';'), input.propsValue, string.Join("','", input.ids)); if (input.columnOptions.IsNotEmptyOrNull() && !string.IsNullOrWhiteSpace(input.keyword)) { var whereStr = new List(); input.columnOptions.Split(",").ToList().ForEach(item => whereStr.Add(string.Format(" {0} like '%{1}%' ", item, input.keyword))); data.Query = string.Format("select * from ({0}) t where {1} ", data.Query.TrimEnd(';'), string.Join(" or ", whereStr)); } if (input.paramList.IsNotEmptyOrNull() && input.paramList.Count > 0) { dicParameters = input.paramList.ToDictionary(x => x.field, y => y.defaultValue); } } if (dicParameters.IsNullOrEmpty()) dicParameters = new Dictionary(); ReplaceParameterValue(data, dicParameters); object output = null; #region 调用接口 if (1.Equals(data.DataType)) { var resTable = await GetData(data); if (type == 0) { // 分页 var dt = GetPageToDataTable(resTable, input.currentPage, input.pageSize); output = new { pagination = new PageResult() { currentPage = input.currentPage, pageSize = input.pageSize, total = resTable.Rows.Count }, list = dt.ToObject>>(), }; } else if (type == 1) { if (input.ids.Any()) { output = resTable.ToObject>>(); } else { output = resTable.ToObject>>().FirstOrDefault(); } } else { output = resTable; } } else if (2.Equals(data.DataType)) { output = data.Query.ToObject(); } else { var result = await GetApiDataByTypePreview(data); var resList = result != null && result.ContainsKey("list") ? result["list"].ToObject>>() : new List>(); if (type == 0) { //if (input.columnOptions.IsNotEmptyOrNull()) //{ // var columList = input.columnOptions.Split(",").ToList(); // resList.ForEach(item => // { // item.Where(x => !columList.Contains(x.Key)).ToList().ForEach(it => item.Remove(it.Key)); // }); //} resList = resList.FindAll(x => x.Where(xx => xx.Value != null && xx.Value.Contains(input.keyword)).Any()); output = new { pagination = new PageResult() { currentPage = input.currentPage, pageSize = input.pageSize, total = resList.Count }, list = resList.Skip((input.currentPage - 1) * input.pageSize).Take(input.pageSize).ToList(), }; } else if (type == 1) { if (input.id != null) { return resList.Find(x => x.ContainsKey(input.propsValue) && x.ContainsValue(input.id)); } else if (input.id == null && input.ids.Count > 0) { return resList.FindAll(x => x.ContainsKey(input.propsValue) && x.Any(it => input.ids.Contains(it.Value))); } } else { output = result; } } #endregion return output; } catch (Exception e) { return new List(); } } /// /// 处理远端数据. /// /// 远端数据ID. /// 指定选项标签为选项对象的某个属性值. /// 指定选项的值为选项对象的某个属性值. /// 指定选项的子选项为选项对象的某个属性值. /// [NonAction] public async Task> GetDynamicList(string propsUrl, string value, string label, string children) { List list = new List(); // 获取远端数据 DataInterfaceEntity? dynamic = await _repository.AsQueryable().Where(x => x.Id == propsUrl && x.DeleteMark == null).FirstAsync(); if (dynamic == null) return list; list = await GetDynamicDataCache(dynamic.Id); if (list == null || list.Count == 0) { list = new List(); // 远端数据 配置参数 List? parameter = new List(); // 未数据处理 var resList = string.Empty; // 数据处理结果 var dataProcessingResults = string.Empty; // 获取数据 switch (dynamic.DataType) { // SQL数据 case 1: { DbLinkEntity? linkEntity = await _repository.AsSugarClient().Queryable().Where(m => m.Id == dynamic.DBLinkId && m.DeleteMark == null).FirstAsync(); if (linkEntity == null) linkEntity = _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); ReplaceParameterValue(dynamic, new Dictionary()); var sql = await GetSqlParameter(dynamic.Query, parameter); DataTable? dt = _dataBaseManager.GetInterFaceData(linkEntity, sql, parameter.ToArray()); resList = dt.ToJsonString(); } break; // 静态数据 case 2: { resList = JValue.Parse(dynamic.Query).ToJsonString(); } break; // Api数据 case 3: { var result = await GetApiDataByTypePreview(dynamic); resList = result.ToJsonString(); } break; } // 处理数据 switch (dynamic.DataType) { // SQL数据 case 1: // Api数据 case 3: if (!dynamic.DataProcessing.IsNullOrEmpty()) { string sheetData = Regex.Match(dynamic.DataProcessing, @"\{(.*)\}", RegexOptions.Singleline).Groups[1].Value; var scriptStr = "var result = function(data){data = JSON.parse(data);" + sheetData + "}"; try { dataProcessingResults = JsEngineUtil.CallFunction(scriptStr, resList).ToJsonString(); } catch (Exception) { dataProcessingResults = string.Empty; } } else { dataProcessingResults = resList.ToJsonString(); } break; // 静态数据 case 2: dataProcessingResults = resList.ToJsonString(); break; } if (!dataProcessingResults.IsNullOrEmpty()) { foreach (JToken? item in JToken.Parse(dataProcessingResults)) { StaticDataModel dynamicDic = new StaticDataModel() { id = item.Value(value), fullName = item.Value(label) }; list.Add(dynamicDic); // 为避免子级有数据. if (item.Value(children) != null && item.Value(children).ToString().IsNotEmptyOrNull()) list.AddRange(GetDynamicInfiniteData(item.Value(children).ToString(), value, label, children)); } await SetDynamicDataCache(dynamic.Id, list); } } return list; } #endregion #region PrivateMethod /// /// 获取动态无限级数据. /// /// /// 指定选项标签为选项对象的某个属性值. /// 指定选项的值为选项对象的某个属性值. /// 指定选项的子选项为选项对象的某个属性值. /// private List GetDynamicInfiniteData(string data, string value, string label, string children) { List list = new List(); foreach (JToken? info in JToken.Parse(data)) { StaticDataModel dic = new StaticDataModel() { id = info.Value(value), fullName = info.Value(label) }; list.Add(dic); if (info.Value(children) != null && info.Value(children).ToString() != string.Empty) list.AddRange(GetDynamicInfiniteData(info.Value(children).ToString(), value, label, children)); } return list; } /// /// 通过连接执行sql. /// /// private async Task connection(string dbLinkId, string sql, string reqMethod) { var link = new DbLinkEntity(); if (!_sqlSugarClient.AsTenant().IsAnyConnection(_configId)) { link = await _sqlSugarClient.Queryable().FirstAsync(x => x.Id == dbLinkId && x.DeleteMark == null); } else { link = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Id == dbLinkId && x.DeleteMark == null); } var tenantLink = link ?? await GetTenantDbLink(); var parameter = new List(); sql = await GetSqlParameter(sql, parameter); if (reqMethod.Equals("3")) { return _dataBaseManager.GetInterFaceData(tenantLink, sql, parameter.ToArray()); } else { _dataBaseManager.ExecuteCommand(tenantLink, sql, parameter.ToArray()); return new DataTable(); } } /// /// 根据不同规则请求接口(预览). /// /// /// private async Task GetApiDataByTypePreview(DataInterfaceEntity entity) { var result = new JObject(); var parameters = entity?.RequestParameters.ToObject>() ?? new List(); var parametersHerader = entity?.RequestHeaders.ToObject>() ?? new List(); var dic = new Dictionary(); var dicHerader = new Dictionary(); dicHerader.Add("JNPF_API", true); if (_userManager.ToKen != null && !_userManager.ToKen.Contains("::")) dicHerader.Add("Authorization", _userManager.ToKen); foreach (var key in parameters) { dic.Add(key.field, key.defaultValue); } foreach (var key in parametersHerader) { dicHerader[key.field] = key.defaultValue; } switch (entity?.RequestMethod) { case "6": result = (await entity.Path.SetHeaders(dicHerader).SetQueries(dic).GetAsStringAsync()).ToObject(); break; case "7": result = (await entity.Path.SetHeaders(dicHerader).SetBody(dic).PostAsStringAsync()).ToObject(); break; } return result.ContainsKey("data") ? result["data"].ToObject() : result; } /// /// DataTable 数据分页. /// /// 数据源. /// 第几页. /// 每页多少条. /// public static DataTable GetPageToDataTable(DataTable dt, int PageIndex, int PageSize) { if (PageIndex == 0) return dt; // 0页代表每页数据,直接返回 if (dt == null) { return new DataTable(); } DataTable newdt = dt.Copy(); newdt.Clear(); // copy dt的框架 int rowbegin = (PageIndex - 1) * PageSize; int rowend = PageIndex * PageSize; // 要展示的数据条数 if (rowbegin >= dt.Rows.Count) return dt; // 源数据记录数小于等于要显示的记录,直接返回dt if (rowend > dt.Rows.Count) rowend = dt.Rows.Count; for (int i = rowbegin; i <= rowend - 1; i++) { DataRow newdr = newdt.NewRow(); DataRow dr = dt.Rows[i]; foreach (DataColumn column in dt.Columns) { newdr[column.ColumnName] = dr[column.ColumnName]; } newdt.Rows.Add(newdr); } return newdt; } /// /// 获取多租户Link. /// /// [NonAction] public async Task GetTenantDbLink() { return new DbLinkEntity { Id = _configId, ServiceName = _dbName, DbType = App.Configuration["ConnectionStrings:DBType"], Host = App.Configuration["ConnectionStrings:Host"], Port = App.Configuration["ConnectionStrings:Port"].ParseToInt(), UserName = App.Configuration["ConnectionStrings:UserName"], Password = App.Configuration["ConnectionStrings:Password"] }; } /// /// 替换参数默认值. /// /// /// [NonAction] public void ReplaceParameterValue(DataInterfaceEntity entity, Dictionary dic) { if (dic.IsNotEmptyOrNull() && entity.IsNotEmptyOrNull() && entity.RequestParameters.IsNotEmptyOrNull()) { var parameterList = entity.RequestParameters.ToList(); foreach (var item in parameterList) { if (dic.Keys.Contains(item.field)) item.defaultValue = HttpUtility.UrlDecode(dic[item.field], Encoding.UTF8); // 对参数解码 if (entity.DataType == 1) { // 将开头和结尾的空格去掉 item.defaultValue = item.defaultValue?.Trim(); // 将逗号替换成一个单引号、逗号、单引号 item.defaultValue = item.defaultValue?.Replace(",", "','"); entity.Query = entity.Query?.Replace("{" + item.field + "}", item.defaultValue); //自动加引号去掉 modify by ly on 20230515 } else entity.Query = entity.Query?.Replace("{" + item.field + "}", item.defaultValue); } entity.RequestParameters = parameterList.ToJsonString(); } } /// /// 获取sql系统变量参数. /// /// /// private async Task GetSqlParameter(string sql, List sugarParameters) { if (_userManager.ToKen != null) { var userInfo = await _userManager.GetUserInfo(); if (sql.Contains("@currentUsersAndSubordinates")) { var subordinates = userInfo.subordinates.ToList(); subordinates.Add(_userManager.UserId); sugarParameters.Add(new SugarParameter("@currentUsersAndSubordinates", subordinates)); } if (sql.Contains("@organization")) { sugarParameters.Add(new SugarParameter("@organization", _userManager?.User?.OrganizeId)); } if (sql.Contains("@currentOrganizationAndSuborganization")) { var subsidiary = userInfo.subsidiary.ToList(); subsidiary.Add(_userManager.User.OrganizeId); sugarParameters.Add(new SugarParameter("@currentOrganizationAndSuborganization", subsidiary)); } if (sql.Contains("@chargeorganization")) { var chargeorganization = userInfo.dataScope.Where(x => x.organizeId == userInfo.organizeId && x.Select).ToList().FirstOrDefault(); sugarParameters.Add(new SugarParameter("@chargeorganization", chargeorganization?.organizeId)); } if (sql.Contains("@currentChargeorganizationAndSuborganization")) { var subsidiary = userInfo.dataScope.Select(x => x.organizeId).Intersect(userInfo.subsidiary).ToList(); sugarParameters.Add(new SugarParameter("@currentChargeorganizationAndSuborganization", subsidiary)); } if (sql.Contains("@user")) { sql = sql.Replace("@user", "'" + _userManager.UserId + "'"); // orcale关键字处理 } } return sql; } /// /// 验证必填参数. /// /// /// private void VerifyRequired(DataInterfaceEntity entity, Dictionary dicParams) { try { if (entity.IsNotEmptyOrNull() && entity.RequestParameters.IsNotEmptyOrNull() && !entity.RequestParameters.Equals("[]")) { var reqParams = entity.RequestParameters.ToList(); if (reqParams.Count > 0) { // 必填参数 var requiredParams = reqParams.Where(x => x.required == "1").ToList(); if (requiredParams.Any() && (dicParams.IsNullOrEmpty() || dicParams.Keys.Count == 0)) throw Oops.Oh(ErrorCode.xg1003); foreach (var item in requiredParams) { if (dicParams.ContainsKey(item.field)) { switch (item.dataType) { case "varchar": if (dicParams[item.field].IsNullOrEmpty()) { throw Oops.Oh(item.field + "不能为空"); } break; case "int": dicParams[item.field].ParseToInt(); break; case "datetime": dicParams[item.field].ParseToDateTime(); break; case "decimal": dicParams[item.field].ParseToDecimal(); break; } } else { throw Oops.Oh(item.field + "不能为空"); } } } } } catch (AppFriendlyException ex) { throw Oops.Oh(ErrorCode.xg1003); } } /// /// 外部接口验证并请求. /// /// /// /// /// private async Task InterfaceVerify(string id, string tenantId, Dictionary dic) { UserAgent userAgent = new UserAgent(App.HttpContext); var authorization = App.HttpContext.Request.Headers["Authorization"].ToString(); if (authorization.IsNullOrEmpty()) throw Oops.Oh(ErrorCode.IO0001); var ymDate = App.HttpContext.Request.Headers["YmDate"].ToString(); if (ymDate.IsNullOrEmpty()) throw Oops.Oh(ErrorCode.IO0002); var appId = authorization.Split("::")[0]; var appSecret = authorization.Split("::")[1]; if (KeyVariable.MultiTenancy) { tenantId = tenantId.IsNullOrEmpty() ? _userManager.TenantId : tenantId; var interFace = App.Configuration["Tenant:MultiTenancyDBInterFace"] + tenantId; var response = await interFace.GetAsStringAsync(); var result = response.ToObject>(); if (result.code != 200) throw Oops.Oh(result.msg); else if (result.data.dotnet == null) throw Oops.Oh(ErrorCode.D1025); if (!_sqlSugarClient.IsAnyConnection(tenantId)) { _sqlSugarClient.AddConnection(new ConnectionConfig() { DbType = (SqlSugar.DbType)Enum.Parse(typeof(SqlSugar.DbType), App.Configuration["ConnectionStrings:DBType"]), ConfigId = tenantId, // 设置库的唯一标识 IsAutoCloseConnection = true, ConnectionString = string.Format($"{App.Configuration["ConnectionStrings:DefaultConnection"]}", result.data.dotnet) }); } _sqlSugarClient.ChangeDatabase(tenantId); _configId = tenantId; _dbName = result.data.dotnet; } var interfaceEntity = await _sqlSugarClient.Queryable().FirstAsync(x => x.AppId == appId && x.DeleteMark == null && x.EnabledMark == 1); if (interfaceEntity.IsNullOrEmpty() || interfaceEntity.DataInterfaceIds.IsNullOrEmpty() || !interfaceEntity.DataInterfaceIds.Contains(id)) throw Oops.Oh(ErrorCode.IO0003); if (interfaceEntity.WhiteList.IsNotEmptyOrNull()) { var ipList = interfaceEntity.WhiteList.Split(",").ToList(); if (!ipList.Contains(App.HttpContext.GetLocalIpAddressToIPv4())) throw Oops.Oh(ErrorCode.D9002); } if (interfaceEntity.UsefulLife.IsNotEmptyOrNull() && interfaceEntity.UsefulLife < DateTime.Now) throw Oops.Oh(ErrorCode.IO0004); if (interfaceEntity.VerifySignature == 1) { if (DateTime.Now > ymDate.TimeStampToDateTime().AddMinutes(1)) throw Oops.Oh(ErrorCode.IO0004); var signature = GetVerifySignature(interfaceEntity, id, ymDate); if (authorization != signature) throw Oops.Oh(ErrorCode.IO0003); } else { if (interfaceEntity.AppSecret != appSecret) throw Oops.Oh(ErrorCode.IO0003); } var sw = new Stopwatch(); sw.Start(); object output = null; var info = await GetInfo(id); if (info != null && info.EnabledMark == 0) throw Oops.Oh(ErrorCode.IO0003); VerifyRequired(info, dic); ReplaceParameterValue(info, dic); if (info.DataType == 1) { var link = new DbLinkEntity(); if (!_sqlSugarClient.AsTenant().IsAnyConnection(_configId)) { link = await _sqlSugarClient.Queryable().FirstAsync(x => x.Id == info.DBLinkId && x.DeleteMark == null); } else { link = await _repository.AsSugarClient().Queryable().FirstAsync(x => x.Id == info.DBLinkId && x.DeleteMark == null); } var tenantLink = link ?? await GetTenantDbLink(); output = _dataBaseManager.GetInterFaceData(tenantLink, info.Query); } else if (info.DataType == 2) { output = info.Query.ToObject(); } else { output = await GetApiDataByTypePreview(info); } if (info.DataProcessing.IsNotEmptyOrNull()) { string sheetData = Regex.Match(info.DataProcessing, @"\{(.*)\}", RegexOptions.Singleline).Groups[1].Value; var scriptStr = "var result = function(data){data = JSON.parse(data);" + sheetData + "}"; output = JsEngineUtil.CallFunction(scriptStr, output.ToJsonString()); } sw.Stop(); #region 插入日志 if (App.HttpContext.IsNotEmptyOrNull()) { var httpContext = App.HttpContext; var headers = httpContext.Request.Headers; var log = new DataInterfaceLogEntity() { Id = SnowflakeIdHelper.NextId(), OauthAppId = appId, InvokId = id, InvokTime = DateTime.Now, InvokIp = httpContext.GetLocalIpAddressToIPv4(), InvokDevice = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue), InvokWasteTime = (int)sw.ElapsedMilliseconds, InvokType = httpContext.Request.Method }; await _sqlSugarClient.Insertable(log).ExecuteCommandAsync(); } #endregion return output; } /// /// HMACSHA256加密. /// /// /// /// /// private string GetVerifySignature(InterfaceOauthEntity entity, string interfaceId, string ymDate) { string secret = entity.AppSecret; string method = "POST"; string urlPath = string.Format("/dev/api/system/DataInterface/{0}/Actions/Response", interfaceId); string YmDate = ymDate; string host = App.HttpContext.Request.Host.ToString(); string source = new StringBuilder().Append(method).Append('\n').Append(urlPath).Append('\n') .Append(YmDate).Append('\n').Append(host).ToString(); using (var hmac = new HMACSHA256(secret.ToBase64String().ToBytes())) { byte[] hashmessage = hmac.ComputeHash(source.ToBytes(Encoding.UTF8)); var signature = hashmessage.ToHexString(); return entity.AppId + "::" + signature; } } /// /// 获取代码生成远端数据缓存. /// /// 远端数据ID. /// private async Task> GetDynamicDataCache(string dynamicId) { string cacheKey = string.Format("{0}{1}_{2}", CommonConst.CodeGenDynamic, _userManager.ConnectionConfig.ConfigId, dynamicId); return await _cacheManager.GetAsync>(cacheKey); } /// /// 保存代码生成远端数据缓存. /// /// 远端数据ID. /// 在线用户列表. /// private async Task SetDynamicDataCache(string dynamicId, List list) { string cacheKey = string.Format("{0}{1}_{2}", CommonConst.CodeGenDynamic, _userManager.ConnectionConfig.ConfigId, dynamicId); return await _cacheManager.SetAsync(cacheKey, list, TimeSpan.FromMinutes(3)); } #endregion }