跳到内容

内容安全

受众:开发者 摘要:Content Safety starter 使用方式、Provider 抽象、keyword / noop / 云端 provider 和自建 AI 模型内容安全接入边界。

Content Safety starter 提供统一的敏感内容检测入口,用于 Blog、Forum、Chat、Mall 评价、用户资料、广告素材等场景。

Content Safety starter 保持轻量:内置 keywordnoopopenaigooglealiyuntencentvolcenginebaiduai-modelself-hosted provider,不引入重量级第三方内容安全 SDK。配置和代码边界按短信、存储等模块的 Provider 模式设计,后续新增内容安全服务商时继续通过 Provider 扩展。

后台敏感词库、检测日志、人工复核任务、批量扫描、文件扫描和 CSV 导出由 spring-open-core-content-safety 承接;后台 API 统一挂载在 /api/v1/content-safety/**,权限字符串使用 content-safety:*,配置前缀使用 spring.open.content-safety.*

何时使用

适合:

  • 发布前检测文本、昵称、签名、评论、聊天消息和视频内容元数据。
  • 按场景决定通过、拒绝或进入人工审核。
  • 给内容审核、违规日志、通知事件和广告素材审核提供统一底座。
  • 给 Video 等业务模块提供统一 action / riskLevel / reason 摘要,由业务模块自行决定公开过滤、待复核展示和播放地址隐藏。
  • 后续替换或组合多个内容安全服务商。

不适合:

  • 全局粗暴拦截所有请求体。
  • 替代富文本 XSS 清洗。
  • 在业务模块里直接调用第三方内容安全 SDK。
  • 把聊天实时消息强制绑定慢速同步检测。

快速开始

按需引入:

xml
<dependency>
    <groupId>com.springopen</groupId>
    <artifactId>spring-open-starter-content-safety</artifactId>
</dependency>

默认启用,未配置敏感词时 keyword provider 会直接通过:

yaml
spring:
  open:
    content-safety:
      default-provider: keyword
      providers:
        keyword:
          provider: keyword
          keywords:
            - spam
            - blocked

keyword provider 的词有两个来源,可同时生效:

  • 配置词:上面的 keywords / regexes 列表,按 provider 级 action-on-match / risk-level-on-match 统一决策。
  • 词源 SPI(ContentSafetyKeywordSource:业务侧注册的扩展词源,每条词自带 matchType(keyword / regex)、riskLevelaction,按词级语义决策。装配 spring-open-core-content-safety 后,后台敏感词管理(content_safety_word 表)会通过内置的数据库词源自动接入:管理员在后台增删改敏感词后最长 30 秒内对所有内容检测生效;action=reject 直接拒绝,action=review 转待复核。词源读库失败时沿用上一份词快照,不阻断内容发布。

配置词与词源词同时命中时整体动作取最严(reject 优先于 review),风险等级取命中项中的最高级。

Facade 使用:

java
ContentSafetyResult result = ContentSafety.check(ContentSafetyRequest.builder()
        .scene("forum.topic")
        .bizType("forum-topic")
        .content("hello")
        .build());

if (result.isRejected()) {
    // 拒绝发布
}

if (result.isReviewRequired()) {
    // 进入人工审核
}

Provider

配置结构:

yaml
spring:
  open:
    content-safety:
      enabled: true
      default-provider: keyword
      fallback-providers:
        - noop
      providers:
        keyword:
          provider: keyword
          enabled: true
          word-set: default
          keywords:
            - blocked
          action-on-match: review
        noop:
          provider: noop
          enabled: true
        openai-main:
          provider: openai
          enabled: false
          api-key: ${OPENAI_API_KEY:}
          model: omni-moderation-latest
        google-main:
          provider: google
          enabled: false
          access-token: ${GOOGLE_CLOUD_LANGUAGE_ACCESS_TOKEN:}
        aliyun-main:
          provider: aliyun
          enabled: false
          endpoint: https://green-cip.cn-shanghai.aliyuncs.com
          service: comment_detection_pro
          access-key-id: ${ALIYUN_CONTENT_SAFETY_ACCESS_KEY_ID:}
          access-key-secret: ${ALIYUN_CONTENT_SAFETY_ACCESS_KEY_SECRET:}
        tencent-main:
          provider: tencent
          enabled: false
          region: ap-guangzhou
          biz-type: TencentCloudDefault
          secret-id: ${TENCENT_CONTENT_SAFETY_SECRET_ID:}
          secret-key: ${TENCENT_CONTENT_SAFETY_SECRET_KEY:}
        volcengine-main:
          provider: volcengine
          enabled: false
          region: cn-north-1
          service: content_security
          access-key-id: ${VOLCENGINE_CONTENT_SAFETY_ACCESS_KEY_ID:}
          access-key-secret: ${VOLCENGINE_CONTENT_SAFETY_ACCESS_KEY_SECRET:}
          properties:
            app-id: ${VOLCENGINE_CONTENT_SAFETY_APP_ID:}
        baidu-main:
          provider: baidu
          enabled: false
          access-token: ${BAIDU_CONTENT_SAFETY_ACCESS_TOKEN:}
        local-model:
          provider: ai-model
          enabled: false
          endpoint: ${LOCAL_CONTENT_SAFETY_ENDPOINT:}
          api-key: ${LOCAL_CONTENT_SAFETY_API_KEY:}
          model: moderation-v1
        private-model:
          provider: self-hosted
          enabled: false
          endpoint: ${PRIVATE_CONTENT_SAFETY_ENDPOINT:}
          api-key: ${PRIVATE_CONTENT_SAFETY_API_KEY:}
          model: moderation-v1

说明:

  • providers 的 map key 是可命名 provider 实例,例如 keywordkeyword-stricttencent-main
  • providers.*.provider 是真实 provider 实现类型,例如 keywordnooptencentaliyunvolcenginebaiduai-modelself-hosted
  • 同一个 provider 实现类型可以配置多个 provider 实例。
  • 业务模块只调用 ContentSafety / ContentSafetyManager,不直接依赖第三方 SDK。

配置

配置默认值说明
spring.open.content-safety.enabledtrue是否启用内容安全 starter
spring.open.content-safety.default-providerkeyword默认 provider
spring.open.content-safety.fallback-providersnoopprovider 不可用时的后备 provider
spring.open.content-safety.providers.*.provider-provider 实例使用的实现类型
spring.open.content-safety.providers.*.enabledtrueprovider 是否启用
spring.open.content-safety.providers.*.endpoint按 provider服务地址;OpenAI 默认 https://api.openai.com/v1/moderations,Google 默认 https://language.googleapis.com/v1/documents:moderateText,阿里云默认 https://green-cip.cn-shanghai.aliyuncs.com,腾讯云默认 https://tms.tencentcloudapi.com,火山默认 https://riskcontrol.volcengineapi.com,百度默认 https://aip.baidubce.com/rest/2.0/solution/v1/text_censor/v2/user_defined,自建模型必须显式配置
spring.open.content-safety.providers.*.timeout10sHTTP 请求超时时间
spring.open.content-safety.providers.*.api-keyOpenAI / 自建模型等 Bearer Token
spring.open.content-safety.providers.*.access-tokenGoogle Cloud Natural Language OAuth Access Token 或百度内容审核 access token
spring.open.content-safety.providers.*.model按 providerOpenAI moderation 模型或自建模型名;OpenAI 默认 omni-moderation-latest
spring.open.content-safety.providers.*.service按 provider阿里云 TextModerationPlus 服务或火山业务风险服务;阿里云默认 comment_detection_pro,火山默认 content_security
spring.open.content-safety.providers.*.access-key-id阿里云 / 火山 AccessKey ID
spring.open.content-safety.providers.*.access-key-secret阿里云 / 火山 AccessKey Secret
spring.open.content-safety.providers.*.secret-id腾讯云 SecretId
spring.open.content-safety.providers.*.secret-key腾讯云 SecretKey
spring.open.content-safety.providers.*.region按 provider腾讯云 / 火山地域;腾讯云默认 ap-guangzhou,火山默认 cn-north-1
spring.open.content-safety.providers.*.biz-type按 provider腾讯云策略 BizType,默认 TencentCloudDefault
spring.open.content-safety.providers.*.properties.app-id火山内容安全应用 ID
spring.open.content-safety.providers.*.properties.actionTextSliceRisk火山 OpenAPI Action
spring.open.content-safety.providers.*.properties.version按 provider火山 API Version 或云厂商扩展版本
spring.open.content-safety.providers.*.properties.signing-servicebusinessSecurity火山 OpenAPI 签名服务名
spring.open.content-safety.providers.*.keywordskeyword provider 使用的关键词
spring.open.content-safety.providers.*.regexeskeyword provider 使用的正则规则
spring.open.content-safety.providers.*.ignore-casetruekeyword / regex 是否忽略大小写
spring.open.content-safety.providers.*.action-on-matchreview命中后的建议动作:allow / review / reject
spring.open.content-safety.providers.*.risk-level-on-matchmedium命中后的风险等级

OpenAI Provider

openai provider 对接 OpenAI Moderations API,适合作为国际化内容审核默认服务:

yaml
spring:
  open:
    content-safety:
      default-provider: openai-main
      providers:
        openai-main:
          provider: openai
          enabled: true
          api-key: ${OPENAI_API_KEY:}
          model: omni-moderation-latest

说明:

  • 默认调用 https://api.openai.com/v1/moderations
  • 官方默认模型为 omni-moderation-latest
  • 命中后默认返回 review,如需直接拒绝可配置 action-on-match: reject
  • OpenAI 返回的分类会转换为 ContentSafetyMatch,前端和业务模块不需要感知 OpenAI 原始响应结构。

参考:

Google Provider

google provider 对接 Google Cloud Natural Language documents:moderateText REST API,适合作为海外内容审核服务的可选方案:

yaml
spring:
  open:
    content-safety:
      default-provider: google-main
      providers:
        google-main:
          provider: google
          enabled: true
          access-token: ${GOOGLE_CLOUD_LANGUAGE_ACCESS_TOKEN:}

说明:

  • 默认调用 https://language.googleapis.com/v1/documents:moderateText
  • Google 官方接口要求 OAuth 授权,本框架不内置服务账号换 token 逻辑,避免引入较重 Google Auth SDK;部署时把外部获取到的短期 access token 注入配置即可。
  • moderationCategories 会按置信度转换为统一 ContentSafetyMatch;默认阈值为 0.4,可通过 properties.threshold 调整。

参考:

Aliyun Provider

aliyun provider 对接阿里云内容安全 TextModerationPlus,适合作为国内内容审核服务的可选方案:

yaml
spring:
  open:
    content-safety:
      default-provider: aliyun-main
      providers:
        aliyun-main:
          provider: aliyun
          enabled: true
          endpoint: https://green-cip.cn-shanghai.aliyuncs.com
          service: comment_detection_pro
          access-key-id: ${ALIYUN_CONTENT_SAFETY_ACCESS_KEY_ID:}
          access-key-secret: ${ALIYUN_CONTENT_SAFETY_ACCESS_KEY_SECRET:}

说明:

  • 默认调用 https://green-cip.cn-shanghai.aliyuncs.com
  • 请求使用阿里云 OpenAPI HMAC-SHA1 签名,不引入 green20220302 SDK。
  • service 可按场景切换,例如 chat_detection_procomment_detection_pronickname_detection_prougc_moderation_byllm 等。
  • Data.RiskLevel=low 转为 allowmedium 转为 reviewhigh 转为 reject

参考:

Tencent Provider

tencent provider 对接腾讯云 TMS TextModeration,适合作为国内内容审核服务:

yaml
spring:
  open:
    content-safety:
      default-provider: tencent-main
      providers:
        tencent-main:
          provider: tencent
          enabled: true
          region: ap-guangzhou
          biz-type: TencentCloudDefault
          secret-id: ${TENCENT_CONTENT_SAFETY_SECRET_ID:}
          secret-key: ${TENCENT_CONTENT_SAFETY_SECRET_KEY:}

说明:

  • 默认调用 https://tms.tencentcloudapi.com
  • 请求使用腾讯云 TC3-HMAC-SHA256 签名。
  • Suggestion=Pass 转为 allowSuggestion=Review 转为 reviewSuggestion=Block 转为 reject
  • 腾讯云返回的 LabelKeywordsScore 会转换为统一 ContentSafetyResult

参考:

Volcengine Provider

volcengine provider 对接火山引擎业务风险识别文本风险接口,适合作为国内内容审核服务的可选方案:

yaml
spring:
  open:
    content-safety:
      default-provider: volcengine-main
      providers:
        volcengine-main:
          provider: volcengine
          enabled: true
          endpoint: https://riskcontrol.volcengineapi.com
          region: cn-north-1
          service: content_security
          access-key-id: ${VOLCENGINE_CONTENT_SAFETY_ACCESS_KEY_ID:}
          access-key-secret: ${VOLCENGINE_CONTENT_SAFETY_ACCESS_KEY_SECRET:}
          properties:
            app-id: ${VOLCENGINE_CONTENT_SAFETY_APP_ID:}

说明:

  • 默认请求 Action=TextSliceRiskVersion=2022-11-07,通过 properties.app-id 传递火山应用 ID。
  • 请求使用火山 OpenAPI HMAC-SHA256 签名,不引入火山 SDK。
  • Decision=Pass 转为 allowBlock / Reject 转为 reject,其他风险决策默认转为 review
  • Data.ResultsFinalLabelDecisionLabelScore 会转换为统一 ContentSafetyResult

参考:

Baidu Provider

baidu provider 对接百度智能云内容审核平台文本接口:

yaml
spring:
  open:
    content-safety:
      default-provider: baidu-main
      providers:
        baidu-main:
          provider: baidu
          enabled: true
          access-token: ${BAIDU_CONTENT_SAFETY_ACCESS_TOKEN:}

说明:

  • 默认调用 https://aip.baidubce.com/rest/2.0/solution/v1/text_censor/v2/user_defined
  • 百度接口使用 access_token 鉴权;本框架不内置 token 换取和刷新逻辑,部署时由外部任务把有效 token 注入配置。
  • conclusionType=1 转为 allow2 转为 reject3 转为 review4 视为 provider 调用失败。
  • data[].hits[].words 会脱敏后转换为统一 ContentSafetyMatch

参考:

AI Model Provider

ai-model / self-hosted provider 面向自建或内网模型服务,使用轻量 HTTP JSON contract,避免 starter 直接绑定具体模型 SDK。两者使用同一请求 / 响应协议;self-hosted 更适合作为私有模型网关的业务可见 provider 名:

yaml
spring:
  open:
    content-safety:
      default-provider: local-model
      providers:
        local-model:
          provider: ai-model
          enabled: true
          endpoint: https://model.example.internal/moderations
          api-key: ${LOCAL_CONTENT_SAFETY_API_KEY:}
          model: moderation-v1

请求体会发送 modelinputcontentTypescenebizType 和请求扩展属性。响应支持以下轻量字段:

json
{
  "action": "review",
  "riskLevel": "medium",
  "reason": "custom-model.flagged",
  "matches": [
    {"type": "label", "category": "spam", "keyword": "coupon", "score": 0.72}
  ]
}

说明:

  • allowed=trueaction=allow|pass 且无高风险时转为 allow
  • action=reject|block|denyriskLevel=high 转为 reject
  • 其他命中默认转为 review

Provider 选择顺序

未显式指定 provider 时,Manager 按顺序选择:

  1. ContentSafetyRouteResolver 返回的候选 provider。
  2. default-provider
  3. fallback-providers

显式指定 provider 时,只使用该 provider。

源码机制骨架

类型机制职责
ContentSafety静态 Facade,给业务模块提供最短检测入口
ContentSafetyManagerProvider将 Facade 绑定到 Spring 容器内的 ContentSafetyManager
ContentSafetyManager检测编排入口,负责请求校验、provider 路由、fallback、事件通知和异常语义
DefaultContentSafetyManager默认 Manager 实现,按显式 provider、路由解析器、默认 provider、fallback provider 的顺序生成候选列表
ContentSafetyRouteResolver场景化 provider 路由扩展点,可按 scene、bizType、用户、语言或租户返回候选 provider
ContentSafetyProviderProvider SPI,只负责调用具体检测策略或外部服务并返回统一结果
ContentSafetyProviderContext已解析的 provider 实例上下文,区分配置实例名和实现类型
ContentSafetyCheckListener检测事件监听器,用于审计、统计或复核任务生成;监听器失败不影响检测结果
ContentSafetyCheckEvent检测事件,记录候选 provider、最终 provider、结果、异常和耗时
ContentSafetyRequest检测请求,只描述业务场景、对象标识、内容类型和待检测文本
ContentSafetyResult统一结果,返回 allow / review / reject 建议、风险等级、命中摘要和轻量 metadata

Provider 实例名和实现类型是两个概念:tencent-maintencent-strict 可以都是 provider: tencent。Manager 先按实例名读取配置,再用实现类型找到对应 ContentSafetyProvider

检测成功或最终失败后都会触发 ContentSafetyCheckListener;监听器异常会被吞掉,不能反向阻塞用户发布、评论或聊天发送。

复杂场景建议写 ContentSafetyRouteResolver,不要在 YAML 里堆路由 DSL:

java
@Bean
ContentSafetyRouteResolver contentSafetyRouteResolver() {
    return request -> {
        if ("chat.message".equals(request.getScene())) {
            return List.of("keyword-chat");
        }
        return List.of();
    };
}

检测事件监听

每次内容安全检测最终成功或失败后,Manager 会发布 ContentSafetyCheckEvent 给所有 ContentSafetyCheckListener

这个扩展点用于后续落库检测日志、运营审计、失败统计和审核任务生成。Listener 失败不会影响本次内容安全判断,避免日志系统异常反向阻塞用户发布、评论或聊天链路。

java
@Bean
ContentSafetyCheckListener contentSafetyCheckListener() {
    return event -> {
        // event.request():业务场景、bizType、bizId、用户和内容类型
        // event.providerCandidates():本次候选 provider
        // event.result():最终检测结果
        // event.exception():最终失败异常
        // event.elapsed():检测耗时
    };
}

业务模块仍然只关心 ContentSafetyResult 的建议动作;检测日志、审核任务和运维报表由 spring-open-core-content-safety 通过 Listener 承接,业务模块只按需贡献批量检测来源或消费检测结果。

已接入模块

当前已有这些业务模块消费内容安全底座:

模块场景rejectreview
Blog文章发布 / 编辑、评论提交拒绝保存并返回业务错误文章转为草稿,评论转为隐藏
Forum主题发布 / 编辑、回复提交拒绝保存并返回业务错误主题 / 回复转为隐藏
Conversation聊天消息发送、附件名称检测拒绝发送,不落库、不推送阻断发送,提示内容需调整
CMS后台批量检测 cms-content 来源不直接修改业务内容检测日志进入内容安全复核队列
Mall后台批量检测 mall-review 来源不直接修改商品评价检测日志进入内容安全复核队列

检测日志由 spring-open-core-content-safety 监听器统一落库,仅记录业务场景、Provider、动作、风险等级、耗时、长度等元数据,不保存被检测标题或正文原文。

聊天消息是实时体验,第一阶段不引入“已发送但待审核”的中间态。消息文本和附件名称会在消息落库、附件绑定、未读更新和 WebSocket 推送前统一检测;命中 rejectreview 都直接阻断发送。

后台批量检测调度只负责重新触发检测和生成检测日志,不直接改 CMS 内容、Blog 文章 / 评论或 Mall 评价状态。当前支持这些 sourceType

  • cms-content:CMS 内容标题、摘要、正文和 SEO 摘要。
  • blog-article:Blog 文章标题、摘要、付费试看和正文。
  • blog-comment:Blog 评论昵称和正文。
  • mall-review:商城评价商品名称、评价正文和商家回复。

内容安全运维日志

spring-open-core-content-safety 已内置检测日志落库监听器。每次内容安全检测成功或失败后,会记录检测元数据到 content_safety_check_log

  • 记录 scene / bizType / bizId / contentType / userId
  • 记录 provider 候选、最终 provider、动作、风险等级、命中数量、耗时和异常摘要。
  • 不记录被检测的标题或正文原文,只记录标题长度和正文长度,避免敏感内容二次沉淀。

后台运维接口:

方法路径说明
POST/api/v1/admin/content-safety/batch-scans按业务来源批量触发内容安全检测
GET/api/v1/content-safety/words分页查询敏感词库
GET/api/v1/content-safety/words/{id}查询敏感词详情
POST/api/v1/content-safety/words新增敏感词
PUT/api/v1/content-safety/words/{id}更新敏感词
POST/api/v1/content-safety/words/{id}/enable启用敏感词
POST/api/v1/content-safety/words/{id}/disable停用敏感词
DELETE/api/v1/content-safety/words/{id}删除敏感词
DELETE/api/v1/content-safety/words批量删除敏感词
GET/api/v1/content-safety/check-logs分页查询检测日志
GET/api/v1/content-safety/check-logs/{id}查询检测日志详情
GET/api/v1/content-safety/review-tasks分页查询需要人工复核的检测任务
GET/api/v1/content-safety/review-tasks/{id}查询需要人工复核的检测任务详情
POST/api/v1/content-safety/review-tasks/{id}/approve将复核任务标记为已通过
POST/api/v1/content-safety/review-tasks/{id}/reject将复核任务标记为已拒绝
POST/api/v1/content-safety/review-tasks/{id}/close将复核任务标记为已关闭
POST/api/v1/content-safety/review-tasks/batch/approve批量将复核任务标记为已通过
POST/api/v1/content-safety/review-tasks/batch/reject批量将复核任务标记为已拒绝
POST/api/v1/content-safety/review-tasks/batch/close批量将复核任务标记为已关闭
POST/api/v1/content-safety/review-tasks/auto-handle-expired按配置批量处理超时仍未人工复核的任务

权限:

  • content-safety:check-log:view
  • content-safety:word:view
  • content-safety:word:create
  • content-safety:word:update
  • content-safety:word:delete
  • content-safety:review-task:view
  • content-safety:review-task:update

敏感词库写入 content_safety_word,同一 wordSet + word 保持唯一;每条规则可维护分类、风险等级、匹配类型、命中动作、启停状态和说明。wordSet 默认 defaultcategory 默认 general,风险等级默认 medium,匹配类型默认 keyword,命中动作默认 review

审核任务入口复用检测日志中 reviewRequired=true 的记录,不额外保存被检测原文。单条和批量复核动作都会通过审批工作流 content-safety.review 校验来源状态、动作、权限快照和备注要求,再只记录 reviewStatus / reviewAction / reviewRemark / reviewedBy / reviewedAt 审计字段,不直接修改 Blog、Forum、Chat、Mall 等业务对象状态;业务侧具体放行、拒绝或超时处理继续由各模块自己的审核状态机或事件联动承接。

reject 要求填写备注,approve / close 可不填备注。人工动作要求调用方具备 content-safety:review-task:update 权限;超时自动处理使用 auto-approve / auto-reject / auto-close 动作,不携带人工操作人。

超时自动处理默认启用,默认动作是 approve,符合“审核未及时处理时默认放行”的开发体验。若业务场景更敏感,可以改为 rejectclose

yaml
spring:
  open:
    content-safety:
        review:
          auto:
            enabled: true
            auto-startup: false
            timeout: 24h
            fixed-delay: 10m
            action: approve
            limit: 100
            remark: 内容安全复核超时自动通过

检测日志落库且需要人工复核时,系统会按 timeout 向专用 content-safety 队列投递 content-safety.review.auto-handle 延迟 Queue 消息;消费时会重新读取复核状态,已经人工处理或不再满足复核条件的记录会安全跳过。auto-startupfixed-delay 仅作为旧固定间隔调度配置保留,默认不再注册周期扫描。后台也可以手动调用 POST /api/v1/content-safety/review-tasks/auto-handle-expired 立即处理一批超时任务。

自动处理只更新内容安全复核审计字段:

  • reviewStatus:按 action 写入 approved / rejected / closed
  • reviewAction:写入 auto-approve / auto-reject / auto-close
  • reviewRemark:写入配置的自动处理备注。
  • reviewedBy:为空,表示系统自动处理。
  • reviewedAt:自动处理时间。

Admin 后台已接入两个运维页面:

页面路由能力
内容安全词库/#/content-safety/words分页、筛选、详情、新增 / 编辑、启用 / 停用、删除 / 批量删除敏感词,并展示词库、分类、风险等级、匹配类型和命中动作
内容安全检测日志/#/content-safety/check-logs分页、筛选、详情、结果状态展示、业务快捷筛选、图片文件批量检测、按当前筛选创建 CSV 导出异步任务,并可把需要复核的记录带入同一业务筛选条件跳转到复核任务页
内容安全复核任务/#/content-safety/review-tasks分页、筛选、接收检测日志页 URL 筛选、业务快捷筛选、详情、通过 / 拒绝 / 关闭复核、批量通过 / 拒绝 / 关闭复核、按当前筛选创建 CSV 导出异步任务、手动触发超时自动处理和检测日志跳转

业务快捷筛选只暴露已经真实接入内容安全 contract 的来源。后端已提供 /api/v1/admin/content-safety/batch-scans 统一触发 CMS 内容、Blog 文章、Blog 评论和 Mall 评价批量检测;Admin 视图后续可按该 contract 接入来源选择和触发按钮,不伪造本地预览数据。

Keyword Provider

keyword provider 支持:

  • 普通关键词匹配。
  • 正则匹配。
  • 大小写忽略。
  • 命中后返回 reviewreject
  • 命中词脱敏返回,避免检测结果泄露完整敏感词。

未配置关键词和正则时,keyword provider 直接通过。

Noop Provider

noop provider 始终通过,适合:

  • 开发环境。
  • 未启用真实内容安全时的 fallback。
  • 单进程隔离诊断或兼容模式。

生产环境不建议只依赖 noop

后续接入

后续第三方 provider 按同一边界扩展:

  • volcengine:火山引擎内容安全。
  • baidu:百度智能云内容审核。
  • ai-model:AI Model 底座成熟后的模型审核。
  • self-hosted:私有化部署或内网自建模型审核服务。

第三方 SDK 只出现在对应 provider 实现内部,不向 Controller、Service、DTO 或业务模块泄露。

与审核关系

内容安全只给出建议动作:

  • allow:可通过。
  • review:进入人工审核。
  • reject:拒绝。

Blog / Forum 第一阶段会先把 review 内容转为草稿或隐藏;Conversation 会在发送前阻断。人工审核任务、审核超时默认动作、审核日志和通知事件由 spring-open-core-content-safety 承接,业务侧具体状态流转继续由各业务模块处理。

验证

bash
./mvnw -pl spring-open-starters/spring-open-starter-content-safety -am test -DskipITs
git diff --check

Released under the Apache License 2.0.