mirror of
https://gitee.com/ccnetcore/Yi
synced 2026-03-02 15:50:54 +08:00
feat: Token 支持请求日志开关并记录 OpenAPI 请求日志
新增 Token 的 IsEnableLog 字段,贯穿领域、应用与 DTO;在 OpenApiService 中根据 Token 配置异步记录请求日志,包含请求体、模型与接口类型,用于后续审计与分析。
This commit is contained in:
@@ -40,6 +40,11 @@ public class TokenGetListOutputDto
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsDisabled { get; set; }
|
public bool IsDisabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用请求日志记录
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnableLog { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建时间
|
/// 创建时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ public class TokenService : ApplicationService
|
|||||||
PremiumQuotaLimit = t.PremiumQuotaLimit,
|
PremiumQuotaLimit = t.PremiumQuotaLimit,
|
||||||
PremiumUsedQuota = usedQuota,
|
PremiumUsedQuota = usedQuota,
|
||||||
IsDisabled = t.IsDisabled,
|
IsDisabled = t.IsDisabled,
|
||||||
|
IsEnableLog = t.IsEnableLog,
|
||||||
CreationTime = t.CreationTime
|
CreationTime = t.CreationTime
|
||||||
};
|
};
|
||||||
}).ToList();
|
}).ToList();
|
||||||
@@ -158,6 +159,7 @@ public class TokenService : ApplicationService
|
|||||||
PremiumQuotaLimit = token.PremiumQuotaLimit,
|
PremiumQuotaLimit = token.PremiumQuotaLimit,
|
||||||
PremiumUsedQuota = 0,
|
PremiumUsedQuota = 0,
|
||||||
IsDisabled = token.IsDisabled,
|
IsDisabled = token.IsDisabled,
|
||||||
|
IsEnableLog = token.IsEnableLog,
|
||||||
CreationTime = token.CreationTime
|
CreationTime = token.CreationTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Volo.Abp.Application.Services;
|
using Volo.Abp.Application.Services;
|
||||||
|
using Volo.Abp.Uow;
|
||||||
using Volo.Abp.Users;
|
using Volo.Abp.Users;
|
||||||
using Yi.Framework.AiHub.Domain.Entities;
|
using Yi.Framework.AiHub.Domain.Entities;
|
||||||
using Yi.Framework.AiHub.Domain.Entities.Chat;
|
using Yi.Framework.AiHub.Domain.Entities.Chat;
|
||||||
using Yi.Framework.AiHub.Domain.Entities.Model;
|
using Yi.Framework.AiHub.Domain.Entities.Model;
|
||||||
|
using Yi.Framework.AiHub.Domain.Entities.OpenApi;
|
||||||
using Yi.Framework.AiHub.Domain.Extensions;
|
using Yi.Framework.AiHub.Domain.Extensions;
|
||||||
using Yi.Framework.AiHub.Domain.Managers;
|
using Yi.Framework.AiHub.Domain.Managers;
|
||||||
using Yi.Framework.AiHub.Domain.Shared.Consts;
|
using Yi.Framework.AiHub.Domain.Shared.Consts;
|
||||||
@@ -33,10 +36,12 @@ public class OpenApiService : ApplicationService
|
|||||||
private readonly PremiumPackageManager _premiumPackageManager;
|
private readonly PremiumPackageManager _premiumPackageManager;
|
||||||
private readonly ISqlSugarRepository<ImageStoreTaskAggregateRoot> _imageStoreRepository;
|
private readonly ISqlSugarRepository<ImageStoreTaskAggregateRoot> _imageStoreRepository;
|
||||||
private readonly ISqlSugarRepository<AiModelEntity> _aiModelRepository;
|
private readonly ISqlSugarRepository<AiModelEntity> _aiModelRepository;
|
||||||
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
public OpenApiService(IHttpContextAccessor httpContextAccessor, ILogger<OpenApiService> logger,
|
public OpenApiService(IHttpContextAccessor httpContextAccessor, ILogger<OpenApiService> logger,
|
||||||
TokenManager tokenManager, AiGateWayManager aiGateWayManager,
|
TokenManager tokenManager, AiGateWayManager aiGateWayManager,
|
||||||
ModelManager modelManager, AiBlacklistManager aiBlacklistManager,
|
ModelManager modelManager, AiBlacklistManager aiBlacklistManager,
|
||||||
IAccountService accountService, PremiumPackageManager premiumPackageManager, ISqlSugarRepository<ImageStoreTaskAggregateRoot> imageStoreRepository, ISqlSugarRepository<AiModelEntity> aiModelRepository)
|
IAccountService accountService, PremiumPackageManager premiumPackageManager, ISqlSugarRepository<ImageStoreTaskAggregateRoot> imageStoreRepository, ISqlSugarRepository<AiModelEntity> aiModelRepository,
|
||||||
|
IServiceScopeFactory serviceScopeFactory)
|
||||||
{
|
{
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@@ -48,6 +53,7 @@ public class OpenApiService : ApplicationService
|
|||||||
_premiumPackageManager = premiumPackageManager;
|
_premiumPackageManager = premiumPackageManager;
|
||||||
_imageStoreRepository = imageStoreRepository;
|
_imageStoreRepository = imageStoreRepository;
|
||||||
_aiModelRepository = aiModelRepository;
|
_aiModelRepository = aiModelRepository;
|
||||||
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -91,6 +97,12 @@ public class OpenApiService : ApplicationService
|
|||||||
null, tokenId,
|
null, tokenId,
|
||||||
CancellationToken.None);
|
CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录请求日志
|
||||||
|
if (tokenValidation.IsEnableLog)
|
||||||
|
{
|
||||||
|
FireAndForgetMessageLog(JsonSerializer.Serialize(input), tokenValidation.Token, tokenValidation.TokenName, input.Model, ModelApiTypeEnum.Completions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -206,6 +218,12 @@ public class OpenApiService : ApplicationService
|
|||||||
null, tokenId,
|
null, tokenId,
|
||||||
CancellationToken.None);
|
CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录请求日志
|
||||||
|
if (tokenValidation.IsEnableLog)
|
||||||
|
{
|
||||||
|
FireAndForgetMessageLog(JsonSerializer.Serialize(input), tokenValidation.Token, tokenValidation.TokenName, input.Model, ModelApiTypeEnum.Messages);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -258,6 +276,12 @@ public class OpenApiService : ApplicationService
|
|||||||
null, tokenId,
|
null, tokenId,
|
||||||
CancellationToken.None);
|
CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录请求日志
|
||||||
|
if (tokenValidation.IsEnableLog)
|
||||||
|
{
|
||||||
|
FireAndForgetMessageLog(JsonSerializer.Serialize(input), tokenValidation.Token, tokenValidation.TokenName, input.Model, ModelApiTypeEnum.Responses);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -318,6 +342,12 @@ public class OpenApiService : ApplicationService
|
|||||||
null, tokenId,
|
null, tokenId,
|
||||||
CancellationToken.None);
|
CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录请求日志
|
||||||
|
if (tokenValidation.IsEnableLog)
|
||||||
|
{
|
||||||
|
FireAndForgetMessageLog(input.GetRawText(), tokenValidation.Token, tokenValidation.TokenName, modelId, ModelApiTypeEnum.GenerateContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 私有
|
#region 私有
|
||||||
@@ -357,5 +387,25 @@ public class OpenApiService : ApplicationService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void FireAndForgetMessageLog(string requestBody, string apiKey, string apiKeyName, string modelId, ModelApiTypeEnum apiType)
|
||||||
|
{
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
|
||||||
|
var manager = scope.ServiceProvider.GetRequiredService<MessageLogManager>();
|
||||||
|
using var uow = uowManager.Begin(requiresNew: true);
|
||||||
|
await manager.CreateAsync(requestBody, apiKey, apiKeyName, modelId, apiType);
|
||||||
|
await uow.CompleteAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "记录消息日志失败, 请求体长度: {RequestBodyLength}", requestBody?.Length ?? 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.Domain.Entities;
|
||||||
|
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AiHub.Domain.Entities.OpenApi;
|
||||||
|
|
||||||
|
[SugarTable("Ai_Message_Log")]
|
||||||
|
public class MessageLogAggregateRoot : Entity<Guid>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 请求内容(httpbody)
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnDataType = "text")]
|
||||||
|
public string? RequestBody { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求apikey
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(Length = 255)]
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求apikey名称
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(Length = 255)]
|
||||||
|
public string ApiKeyName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime CreationTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模型id
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(Length = 64)]
|
||||||
|
public string ModelId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// api类型
|
||||||
|
/// </summary>
|
||||||
|
public ModelApiTypeEnum ApiType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// api类型名称
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(Length = 16)]
|
||||||
|
public string ApiTypeName { get; set; }
|
||||||
|
}
|
||||||
@@ -51,6 +51,11 @@ public class TokenAggregateRoot : FullAuditedAggregateRoot<Guid>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsDisabled { get; set; }
|
public bool IsDisabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用请求日志记录(仅数据库手动修改)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnableLog { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查Token是否可用
|
/// 检查Token是否可用
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using Volo.Abp.Domain.Services;
|
||||||
|
using Yi.Framework.AiHub.Domain.Entities.OpenApi;
|
||||||
|
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AiHub.Domain.Managers;
|
||||||
|
|
||||||
|
public class MessageLogManager : DomainService
|
||||||
|
{
|
||||||
|
private readonly ISqlSugarRepository<MessageLogAggregateRoot> _repository;
|
||||||
|
|
||||||
|
public MessageLogManager(ISqlSugarRepository<MessageLogAggregateRoot> repository)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建消息日志
|
||||||
|
/// </summary>
|
||||||
|
public async Task CreateAsync(string requestBody, string apiKey, string apiKeyName, string modelId, ModelApiTypeEnum apiType)
|
||||||
|
{
|
||||||
|
var entity = new MessageLogAggregateRoot
|
||||||
|
{
|
||||||
|
RequestBody = requestBody,
|
||||||
|
ApiKey = apiKey,
|
||||||
|
ApiKeyName = apiKeyName,
|
||||||
|
ModelId = modelId,
|
||||||
|
ApiType = apiType,
|
||||||
|
ApiTypeName = apiType.ToString(),
|
||||||
|
CreationTime = DateTime.Now
|
||||||
|
};
|
||||||
|
await _repository.InsertAsync(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,16 @@ public class TokenValidationResult
|
|||||||
/// token
|
/// token
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Token名称
|
||||||
|
/// </summary>
|
||||||
|
public string TokenName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用请求日志记录
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnableLog { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TokenManager : DomainService
|
public class TokenManager : DomainService
|
||||||
@@ -117,7 +127,9 @@ public class TokenManager : DomainService
|
|||||||
{
|
{
|
||||||
UserId = entity.UserId,
|
UserId = entity.UserId,
|
||||||
TokenId = entity.Id,
|
TokenId = entity.Id,
|
||||||
Token = entity.Token
|
Token = entity.Token,
|
||||||
|
TokenName = entity.Name,
|
||||||
|
IsEnableLog = entity.IsEnableLog
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ namespace Yi.Abp.Web
|
|||||||
var app = context.GetApplicationBuilder();
|
var app = context.GetApplicationBuilder();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
// app.ApplicationServices.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient.CodeFirst.InitTables<RankingItemAggregateRoot>();
|
//app.ApplicationServices.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient.CodeFirst.InitTables<MessageLogAggregateRoot>();
|
||||||
// app.ApplicationServices.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient.CodeFirst.InitTables<ActivationCodeRecordAggregateRoot>();
|
// app.ApplicationServices.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient.CodeFirst.InitTables<ActivationCodeRecordAggregateRoot>();
|
||||||
// app.ApplicationServices.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient.CodeFirst.InitTables<UsageStatisticsAggregateRoot>();
|
// app.ApplicationServices.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient.CodeFirst.InitTables<UsageStatisticsAggregateRoot>();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user