阿里云图片审核集成方案.md 21.1 KB

阿里云图片审核集成方案

文档日期: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.csUploader(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.csUploadBase64Image([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-Typeapplication/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调用
  • 处理审核结果解析
  • 统一异常处理

接口定义

public interface IImageModerationService
{
    /// <summary>
    /// 图片审核(同步检测)
    /// </summary>
    /// <param name="imageBytes">图片字节数组</param>
    /// <param name="imageUrl">图片URL(可选,如果提供URL则优先使用URL审核)</param>
    /// <returns>审核结果</returns>
    Task<ImageModerationResult> ScanImageAsync(byte[] imageBytes, string imageUrl = null);

    /// <summary>
    /// 图片审核(从本地文件路径)
    /// </summary>
    /// <param name="filePath">本地文件路径</param>
    /// <returns>审核结果</returns>
    Task<ImageModerationResult> ScanImageFromFileAsync(string filePath);
}

审核结果模型

public class ImageModerationResult
{
    /// <summary>
    /// 是否通过审核
    /// </summary>
    public bool IsPass { get; set; }

    /// <summary>
    /// 审核建议(pass:通过,review:需要人工审核,block:拒绝)
    /// </summary>
    public string Suggestion { get; set; }

    /// <summary>
    /// 风险等级(normal:正常,low:低风险,medium:中风险,high:高风险)
    /// </summary>
    public string RiskLevel { get; set; }

    /// <summary>
    /// 违规类型列表
    /// </summary>
    public List<string> Labels { get; set; }

    /// <summary>
    /// 错误信息(审核失败时的错误描述)
    /// </summary>
    public string ErrorMessage { get; set; }

    /// <summary>
    /// 审核详情(JSON格式的原始响应)
    /// </summary>
    public string Details { get; set; }
}

4.2 配置项添加

配置文件appsettings.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

注册代码

#region 阿里云图片审核

var imageModerationEnabled = App.Configuration["NCC_App:ImageModeration:Enabled"] == "true";
if (imageModerationEnabled)
{
    services.AddScoped<IImageModerationService, ImageModerationService>();
}

#endregion

4.4 FileService 改造

4.4.1 Uploader 方法改造

改造位置FileService.csUploader 方法

改造逻辑

[HttpPost("Uploader/{type}")]
[AllowAnonymous]
public async Task<dynamic> 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<IImageModerationService>();
            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.csUploadBase64Image 方法

改造逻辑

[HttpPost("UploadBase64Image")]
[AllowAnonymous]
public async Task<dynamic> 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<IImageModerationService>();
                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 方法

功能:判断文件是否为图片类型

代码

[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"blockreview都拒绝
  • 宽松模式SuggestionLevel: "review",仅block拒绝,review允许上传

5.2 风险等级阈值(RiskLevel)

等级 说明 处理方式
normal 正常 允许上传
low 低风险 可配置:允许上传或拒绝上传
medium 中风险 可配置:允许上传或拒绝上传
high 高风险 拒绝上传

配置建议

  • 严格模式RiskLevel: "high",仅high拒绝
  • 中等模式RiskLevel: "medium"mediumhigh都拒绝
  • 宽松模式RiskLevel: "low"lowmediumhigh都拒绝

5.3 审核场景(Scenes)

可选场景

  • porn:涉黄检测
  • terrorism:涉暴涉恐检测
  • ad:广告检测
  • qrcode:二维码检测
  • live:不良场景检测
  • logo:Logo检测

配置建议

"Scenes": ["porn", "terrorism", "ad", "qrcode"]

六、异常处理策略

6.1 审核服务异常

场景:审核服务不可用、网络异常、API调用失败等

处理策略(可配置):

  1. 严格模式:审核服务异常时拒绝上传
  2. 宽松模式:审核服务异常时允许上传(推荐)

实现

catch (Exception ex)
{
    // 根据配置决定是否继续上传
    var failOnError = _configuration["NCC_App:ImageModeration:FailOnError"] == "true";
    if (failOnError)
    {
        throw NCCException.Oh("图片审核服务暂时不可用,请稍后重试");
    }
    // 否则继续上传(降级策略)
}

6.2 审核超时

场景:审核接口响应时间过长

处理策略

  • 设置超时时间(如:5秒)
  • 超时后根据配置决定:继续上传或拒绝上传

实现

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. 审核耗时

    • 目标:单张图片审核耗时
    • 测试:上传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月
状态:待实施