# 阿里云图片审核集成方案 **文档日期**:2026年1月 **目标**:在图片上传流程中集成阿里云内容安全(图片审核)服务,自动识别涉黄、涉暴等违规内容 --- ## 一、当前上传流程梳理 ### 1.1 标准文件上传流程(Uploader) ``` 1. 接收文件(IFormFile) 2. 验证文件类型(AllowFileType) 3. 生成文件路径和文件名(yyyyMMdd_xxx.ext) 4. 【当前】先上传到服务器本地 5. 【当前】从服务器本地上传到OSS 6. 【当前】OSS上传成功 → 删除本地文件 7. 【当前】OSS上传失败 → 保留本地文件 8. 返回URL(OSS成功用OSS URL,失败用本地URL) ``` **接口位置**:`FileService.cs` → `Uploader(string type, IFormFile file)` **接口路径**:`POST /api/File/Uploader/{type}` --- ### 1.2 Base64图片上传流程(UploadBase64Image) ``` 1. 接收Base64数据 2. 解析Base64数据(ParseBase64Data) 3. 验证图片格式(IsValidImageFormat) 4. 生成文件路径和文件名 5. 【当前】直接上传到OSS(不经过本地) 6. 返回OSS访问URL ``` **接口位置**:`FileService.cs` → `UploadBase64Image([FromBody] Base64ImageUploadInput input)` **接口路径**:`POST /api/File/UploadBase64Image` **注意**:Base64上传当前是直接上传到OSS,没有本地备份流程。 --- ### 1.3 关键代码位置 | 方法 | 位置 | 行数范围 | 说明 | |------|------|----------|------| | `Uploader` | `FileService.cs` | 101-159 | 标准文件上传主方法 | | `UploadBase64Image` | `FileService.cs` | 1114-1209 | Base64图片上传主方法 | | `UploadFileToLocalThenOSS` | `FileService.cs` | 540-630 | 先本地后OSS上传逻辑 | | `GetOSSAccessUrl` | `FileService.cs` | 716-780 | 获取OSS访问URL | --- ## 二、阿里云图片审核服务说明 ### 2.1 服务名称 - **服务名称**:内容安全(Content Moderation) - **产品名称**:阿里云内容安全 - **API接口**:图片同步检测 `/green/image/scan` ### 2.2 检测能力 | 检测类型 | 说明 | 风险等级 | |---------|------|----------| | **涉黄** | 色情、低俗、性感等 | 高 | | **涉暴** | 暴力、血腥、恐怖等 | 高 | | **广告** | 二维码、广告文字等 | 中 | | **违规文字** | OCR识别图片中的文字并审核 | 中 | | **其他** | 政治敏感、违禁品等 | 高 | ### 2.3 接口信息 **接口地址**:`https://green.cn-shanghai.aliyuncs.com/green/image/scan` **请求方式**:POST **Content-Type**:`application/json` **认证方式**:AccessKey签名认证(与OSS使用相同的AccessKey) **响应格式**:JSON --- ## 三、集成方案设计 ### 3.1 集成位置 **最佳集成点**:在**保存到本地之后、上传到OSS之前**进行审核 **原因**: 1. ✅ 审核需要图片数据,本地已有文件,可直接读取 2. ✅ 审核通过后再上传OSS,避免违规内容上传到OSS 3. ✅ 审核不通过时,保留本地文件,不上传OSS 4. ✅ 不影响现有流程,只是增加审核步骤 ### 3.2 改造后的流程 #### 3.2.1 标准文件上传流程(改造后) ``` 1. 接收文件(IFormFile) 2. 验证文件类型(AllowFileType) 3. 生成文件路径和文件名(yyyyMMdd_xxx.ext) 4. 先上传到服务器本地 5. 【新增】调用阿里云图片审核接口 6. 【新增】审核不通过 → 保留本地文件,返回错误提示(不上传OSS) 7. 【新增】审核通过 → 继续流程 8. 从服务器本地上传到OSS 9. OSS上传成功 → 删除本地文件 10. OSS上传失败 → 保留本地文件 11. 返回URL(OSS成功用OSS URL,失败用本地URL) ``` #### 3.2.2 Base64图片上传流程(改造后) ``` 1. 接收Base64数据 2. 解析Base64数据(ParseBase64Data) 3. 验证图片格式(IsValidImageFormat) 4. 生成文件路径和文件名 5. 【新增】先保存Base64数据到服务器本地(临时文件) 6. 【新增】调用阿里云图片审核接口 7. 【新增】审核不通过 → 保留本地临时文件,返回错误提示(不上传OSS) 8. 【新增】审核通过 → 继续流程 9. 从服务器本地上传到OSS 10. OSS上传成功 → 删除本地临时文件 11. OSS上传失败 → 保留本地临时文件 12. 返回OSS访问URL ``` --- ## 四、技术实现方案 ### 4.1 创建图片审核服务类 **文件位置**:`netcore/src/Modularity/System/NCC.System/Service/Common/ImageModerationService.cs` **功能**: - 封装阿里云图片审核API调用 - 处理审核结果解析 - 统一异常处理 **接口定义**: ```csharp public interface IImageModerationService { /// /// 图片审核(同步检测) /// /// 图片字节数组 /// 图片URL(可选,如果提供URL则优先使用URL审核) /// 审核结果 Task ScanImageAsync(byte[] imageBytes, string imageUrl = null); /// /// 图片审核(从本地文件路径) /// /// 本地文件路径 /// 审核结果 Task ScanImageFromFileAsync(string filePath); } ``` **审核结果模型**: ```csharp public class ImageModerationResult { /// /// 是否通过审核 /// public bool IsPass { get; set; } /// /// 审核建议(pass:通过,review:需要人工审核,block:拒绝) /// public string Suggestion { get; set; } /// /// 风险等级(normal:正常,low:低风险,medium:中风险,high:高风险) /// public string RiskLevel { get; set; } /// /// 违规类型列表 /// public List Labels { get; set; } /// /// 错误信息(审核失败时的错误描述) /// public string ErrorMessage { get; set; } /// /// 审核详情(JSON格式的原始响应) /// public string Details { get; set; } } ``` --- ### 4.2 配置项添加 **配置文件**:`appsettings.json` **新增配置项**: ```json { "NCC_App": { "AliyunOSS": { "AccessKeyId": "...", "AccessKeySecret": "...", "Endpoint": "...", "Region": "..." }, "ImageModeration": { "Enabled": true, "Endpoint": "https://green.cn-shanghai.aliyuncs.com", "Region": "cn-shanghai", "AccessKeyId": "", // 如果为空,使用AliyunOSS的AccessKeyId "AccessKeySecret": "", // 如果为空,使用AliyunOSS的AccessKeySecret "Scenes": ["porn", "terrorism", "ad", "qrcode", "live", "logo"], // 审核场景 "SuggestionLevel": "block", // 审核建议级别:pass/review/block "RiskLevel": "high" // 风险等级阈值:normal/low/medium/high } } } ``` **配置说明**: - `Enabled`:是否启用图片审核(可配置开关) - `Endpoint`:内容安全服务端点(默认:`https://green.cn-shanghai.aliyuncs.com`) - `Region`:服务区域(默认:`cn-shanghai`) - `AccessKeyId/AccessKeySecret`:如果为空,复用OSS的AccessKey - `Scenes`:审核场景列表 - `SuggestionLevel`:审核建议级别,`block`表示拒绝,`review`表示需要人工审核,`pass`表示通过 - `RiskLevel`:风险等级阈值,超过此等级视为违规 --- ### 4.3 服务注册 **文件位置**:`Startup.cs` **注册代码**: ```csharp #region 阿里云图片审核 var imageModerationEnabled = App.Configuration["NCC_App:ImageModeration:Enabled"] == "true"; if (imageModerationEnabled) { services.AddScoped(); } #endregion ``` --- ### 4.4 FileService 改造 #### 4.4.1 Uploader 方法改造 **改造位置**:`FileService.cs` → `Uploader` 方法 **改造逻辑**: ```csharp [HttpPost("Uploader/{type}")] [AllowAnonymous] public async Task Uploader(string type, IFormFile file) { // ... 现有代码:验证文件类型、生成路径和文件名 ... // 先上传到本地 var (ossSuccess, localPath, ossPath) = await UploadFileToLocalThenOSS( file, _filePath, ossFilePath, _fileName, forceStoreType); // 【新增】图片审核逻辑 var imageModerationEnabled = _configuration["NCC_App:ImageModeration:Enabled"] == "true"; if (imageModerationEnabled && IsImageFile(fileType)) { try { var moderationService = _serviceProvider.GetService(); if (moderationService != null && !string.IsNullOrEmpty(localPath) && File.Exists(localPath)) { var moderationResult = await moderationService.ScanImageFromFileAsync(localPath); if (!moderationResult.IsPass) { // 审核不通过,保留本地文件,返回错误提示(不上传OSS) throw NCCException.Oh($"图片审核未通过:{moderationResult.ErrorMessage ?? "图片包含违规内容"}"); } } } catch (NCCException) { // 审核失败异常,直接抛出 throw; } catch (Exception ex) { // 审核服务异常,根据配置决定是否继续上传(降级策略) var failOnError = _configuration["NCC_App:ImageModeration:FailOnError"] == "true"; if (failOnError) { throw NCCException.Oh("图片审核服务暂时不可用,请稍后重试"); } // 否则继续上传(降级策略) } } // ... 现有代码:返回URL ... } ``` **关键点**: - ✅ 审核在本地文件保存之后、OSS上传之前 - ✅ 审核不通过时保留本地文件,返回错误(不上传OSS) - ✅ 审核通过后上传OSS,OSS上传成功则删除本地文件 - ✅ 审核服务异常时,可选择降级策略(继续上传或拒绝上传) --- #### 4.4.2 UploadBase64Image 方法改造 **改造位置**:`FileService.cs` → `UploadBase64Image` 方法 **改造逻辑**: ```csharp [HttpPost("UploadBase64Image")] [AllowAnonymous] public async Task UploadBase64Image([FromBody] Base64ImageUploadInput input) { // ... 现有代码:解析Base64、验证格式、生成路径 ... // 【新增】先保存Base64数据到本地临时文件 string tempLocalPath = null; try { var tempLocalDir = Path.Combine(FileVariable.TempFilePath, "moderation"); if (!Directory.Exists(tempLocalDir)) { Directory.CreateDirectory(tempLocalDir); } tempLocalPath = Path.Combine(tempLocalDir, fileName); await File.WriteAllBytesAsync(tempLocalPath, imageData); // 【新增】图片审核逻辑 var imageModerationEnabled = _configuration["NCC_App:ImageModeration:Enabled"] == "true"; if (imageModerationEnabled) { try { var moderationService = _serviceProvider.GetService(); if (moderationService != null) { var moderationResult = await moderationService.ScanImageFromFileAsync(tempLocalPath); if (!moderationResult.IsPass) { // 审核不通过,保留临时文件,返回错误提示(不上传OSS) throw NCCException.Oh($"图片审核未通过:{moderationResult.ErrorMessage ?? "图片包含违规内容"}"); } } } catch (NCCException) { throw; } catch (Exception ex) { // 审核服务异常,根据配置决定是否继续上传(降级策略) var failOnError = _configuration["NCC_App:ImageModeration:FailOnError"] == "true"; if (failOnError) { throw NCCException.Oh("图片审核服务暂时不可用,请稍后重试"); } // 否则继续上传(降级策略) } } // 从临时文件上传到OSS using (var stream = new FileStream(tempLocalPath, FileMode.Open)) { await _oSSServiceFactory.Create("aliyun").PutObjectAsync(bucketName, ossPath, stream); } // OSS上传成功,删除临时文件 if (File.Exists(tempLocalPath)) { File.Delete(tempLocalPath); } // ... 返回URL ... } catch { // 异常时清理临时文件 if (!string.IsNullOrEmpty(tempLocalPath) && File.Exists(tempLocalPath)) { try { File.Delete(tempLocalPath); } catch { } } throw; } } ``` **关键点**: - ✅ Base64上传改为先保存到本地临时文件 - ✅ 审核通过后再上传到OSS,OSS上传成功则删除临时文件 - ✅ 审核不通过时保留临时文件,返回错误(不上传OSS) --- ### 4.5 辅助方法 #### 4.5.1 IsImageFile 方法 **功能**:判断文件是否为图片类型 **代码**: ```csharp [NonAction] private bool IsImageFile(string fileType) { var imageTypes = new[] { "jpg", "jpeg", "png", "gif", "bmp", "webp" }; return imageTypes.Contains(fileType.ToLower()); } ``` --- ## 五、审核策略配置 ### 5.1 审核建议级别(SuggestionLevel) | 级别 | 说明 | 处理方式 | |------|------|----------| | `pass` | 通过 | 允许上传 | | `review` | 需要人工审核 | 可配置:允许上传或拒绝上传 | | `block` | 拒绝 | 拒绝上传,返回错误 | **配置建议**: - **严格模式**:`SuggestionLevel: "block"`,`block`和`review`都拒绝 - **宽松模式**:`SuggestionLevel: "review"`,仅`block`拒绝,`review`允许上传 --- ### 5.2 风险等级阈值(RiskLevel) | 等级 | 说明 | 处理方式 | |------|------|----------| | `normal` | 正常 | 允许上传 | | `low` | 低风险 | 可配置:允许上传或拒绝上传 | | `medium` | 中风险 | 可配置:允许上传或拒绝上传 | | `high` | 高风险 | 拒绝上传 | **配置建议**: - **严格模式**:`RiskLevel: "high"`,仅`high`拒绝 - **中等模式**:`RiskLevel: "medium"`,`medium`和`high`都拒绝 - **宽松模式**:`RiskLevel: "low"`,`low`、`medium`、`high`都拒绝 --- ### 5.3 审核场景(Scenes) **可选场景**: - `porn`:涉黄检测 - `terrorism`:涉暴涉恐检测 - `ad`:广告检测 - `qrcode`:二维码检测 - `live`:不良场景检测 - `logo`:Logo检测 **配置建议**: ```json "Scenes": ["porn", "terrorism", "ad", "qrcode"] ``` --- ## 六、异常处理策略 ### 6.1 审核服务异常 **场景**:审核服务不可用、网络异常、API调用失败等 **处理策略**(可配置): 1. **严格模式**:审核服务异常时拒绝上传 2. **宽松模式**:审核服务异常时允许上传(推荐) **实现**: ```csharp catch (Exception ex) { // 根据配置决定是否继续上传 var failOnError = _configuration["NCC_App:ImageModeration:FailOnError"] == "true"; if (failOnError) { throw NCCException.Oh("图片审核服务暂时不可用,请稍后重试"); } // 否则继续上传(降级策略) } ``` --- ### 6.2 审核超时 **场景**:审核接口响应时间过长 **处理策略**: - 设置超时时间(如:5秒) - 超时后根据配置决定:继续上传或拒绝上传 **实现**: ```csharp using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5))) { try { var moderationResult = await moderationService.ScanImageFromFileAsync(localPath) .WithCancellation(cts.Token); } catch (OperationCanceledException) { // 超时处理,根据配置决定是否继续上传 var failOnError = _configuration["NCC_App:ImageModeration:FailOnError"] == "true"; if (failOnError) { throw NCCException.Oh("图片审核超时,请稍后重试"); } } } ``` --- ## 七、性能优化 ### 7.1 异步审核 ✅ 已使用 `async/await`,不会阻塞主线程 ### 7.2 审核缓存(可选) **场景**:相同图片重复上传 **实现**: - 计算图片MD5值 - 缓存审核结果(Redis或内存缓存) - 相同图片直接使用缓存结果 **注意**:需要评估缓存成本和收益 --- ### 7.3 批量审核(可选) **场景**:一次上传多张图片 **实现**: - 使用阿里云批量审核接口 `/green/image/batchscan` - 减少API调用次数 **注意**:当前流程是单张上传,暂不需要 --- ## 八、日志记录 **说明**:企业内部使用,暂不需要日志记录功能。 --- ## 九、测试方案 ### 9.1 功能测试 1. **正常图片上传**: - ✅ 审核通过,正常上传到OSS - ✅ 返回OSS URL 2. **违规图片上传**: - ✅ 审核不通过,拒绝上传 - ✅ 返回错误提示 - ✅ 本地文件已删除 3. **审核服务异常**: - ✅ 根据配置决定是否继续上传 --- ### 9.2 性能测试 1. **审核耗时**: - 目标:单张图片审核耗时 < 2秒 - 测试:上传100张图片,统计平均耗时 2. **并发测试**: - 目标:支持10个并发上传 - 测试:同时上传10张图片 --- ### 9.3 边界测试 1. **大图片**: - 测试:上传10MB图片 - 验证:审核是否正常 2. **小图片**: - 测试:上传1KB图片 - 验证:审核是否正常 3. **特殊格式**: - 测试:上传WebP、GIF动图 - 验证:审核是否支持 --- ## 十、配置清单 ### 10.1 必需配置 | 配置项 | 位置 | 说明 | |--------|------|------| | `ImageModeration:Enabled` | `appsettings.json` | 是否启用图片审核 | | `ImageModeration:Endpoint` | `appsettings.json` | 内容安全服务端点 | | `ImageModeration:Region` | `appsettings.json` | 服务区域 | | `ImageModeration:AccessKeyId` | `appsettings.json` | AccessKey ID(可选,可复用OSS) | | `ImageModeration:AccessKeySecret` | `appsettings.json` | AccessKey Secret(可选,可复用OSS) | --- ### 10.2 可选配置 | 配置项 | 默认值 | 说明 | |--------|--------|------| | `ImageModeration:Scenes` | `["porn", "terrorism", "ad", "qrcode"]` | 审核场景 | | `ImageModeration:SuggestionLevel` | `"block"` | 审核建议级别 | | `ImageModeration:RiskLevel` | `"high"` | 风险等级阈值 | | `ImageModeration:FailOnError` | `"false"` | 审核服务异常时是否拒绝上传 | | `ImageModeration:Timeout` | `5` | 审核超时时间(秒) | --- ## 十一、实施步骤 ### 11.1 第一阶段:基础集成 1. ✅ 创建 `ImageModerationService` 服务类 2. ✅ 添加配置项到 `appsettings.json` 3. ✅ 在 `Startup.cs` 注册服务 4. ✅ 改造 `Uploader` 方法,集成审核逻辑 5. ✅ 测试标准文件上传流程 **预计工作量**:2-3人天 --- ### 11.2 第二阶段:Base64上传改造 1. ✅ 改造 `UploadBase64Image` 方法 2. ✅ 添加临时文件保存逻辑 3. ✅ 集成审核逻辑 4. ✅ 测试Base64上传流程 **预计工作量**:1-2人天 --- ### 11.3 第三阶段:优化与完善 1. ✅ 优化异常处理 2. ✅ 性能测试与优化 3. ✅ 文档完善 **预计工作量**:0.5人天 --- ## 十二、风险评估 ### 12.1 技术风险 | 风险 | 影响 | 应对措施 | |------|------|----------| | 审核服务不可用 | 高 | 实现降级策略,允许配置是否继续上传 | | 审核超时 | 中 | 设置超时时间,超时后根据配置决定 | | 审核误判 | 中 | 提供人工审核机制,支持人工复查 | | 性能影响 | 低 | 异步审核,不阻塞主流程 | --- ### 12.2 业务风险 | 风险 | 影响 | 应对措施 | |------|------|----------| | 正常图片被误判 | 中 | 提供申诉机制,人工审核 | | 违规图片漏检 | 高 | 定期优化审核策略,人工抽检 | | 审核成本 | 低 | 按量计费,成本可控 | --- ## 十三、后续优化建议 ### 13.1 人工审核机制(可选) - 审核结果为 `review` 时,进入人工审核队列 - 提供管理后台,支持人工审核 - 审核通过后允许上传 --- ### 13.2 审核结果统计 - 统计审核通过率 - 统计违规类型分布 - 生成审核报告 --- ### 13.3 白名单机制 - 支持配置白名单(特定用户或IP) - 白名单用户跳过审核 --- ## 十四、总结 ### 14.1 集成方案要点 1. ✅ **集成位置**:本地保存之后、OSS上传之前 2. ✅ **审核服务**:创建独立的 `ImageModerationService` 服务类 3. ✅ **配置灵活**:支持开关、审核级别、异常处理策略等配置 4. ✅ **降级策略**:审核服务异常时可选择继续上传或拒绝上传 5. ✅ **文件处理**:审核不通过保留本地文件,审核通过后上传OSS并删除本地文件 --- ### 14.2 改造影响 - ✅ **最小化影响**:仅在上传流程中增加审核步骤 - ✅ **向后兼容**:可通过配置开关控制是否启用审核 - ✅ **性能可控**:异步审核,不阻塞主流程 --- **文档版本**:v1.0 **最后更新**:2026年1月 **状态**:待实施