# 阿里云图片审核集成方案
**文档日期**: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月
**状态**:待实施