小程序:UGC自定义发布内容接入微信公众平台内容安全API(imgSecCheck、msgSecCheck、mediaCheckAsync)

文章目录

问题

你好,你的小程序涉及提供UGC自定义发布内容功能,但服务体验流程有特定限制,环节暂无法正常体验小程序功能及确认小程序有内容安全识别能力。为避免您的小程序被滥用,建议接入微信公众平台内容安全API(imgSecCheck、msgSecCheck、mediaCheckAsync)能力参考文档,接入后请按文档"示例"指示进行并保存接口返回值的录屏,将接口调用成功录屏及小程序服务截图上传后再提交代码。

分析

一、msg_sec_check

msgSecCheck 是微信小程序服务端的文本内容安全检测接口,用于检查文本是否含违法违规内容(如涉政、色情、辱骂、广告等),必须在开发者服务器 / 云函数调用,不可在小程序前端直接调用

接口基本信息
核心参数(Body)
javascript 复制代码
{
  "content": "待检测文本",
  "version": 2,// 固定为 2(最新版)
  "scene": 2,// 场景值(1 = 资料 / 昵称,2 = 评论,3 = 论坛,4 = 其他)
  "openid": "用户openid(可选)",
  "title": "标题(可选)",
  "nickname": "用户昵称(可选)"
}
  • scene
javascript 复制代码
1 资料:昵称、头像说明、个性签名
2 评论:短文本、留言、评论、弹幕、许愿墙 / 祈福语
3 论坛:长帖子、文章、主题帖
4 社交日志:个人动态、朋友圈式内容、心愿 / 日记类
返回结果
  • errcode=0:调用成功
  • result.suggest:pass(通过)、risky(可疑)、block(违规)
获取 access_token(调用必备)

access_token 是微信后台接口的全局调用凭证,有效期 2 小时(7200s),需服务端缓存刷新。

  1. 获取 AppID & AppSecret
    小程序后台 → 开发管理 → 开发设置 → 复制 AppID、AppSecret(妥善保管,不可泄露)
  2. 获取接口(GET)
javascript 复制代码
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=你的AppID&secret=你的AppSecret
  1. 返回示例
javascript 复制代码
{
  "access_token": "61_9sX...",
  "expires_in": 7200,
  "errcode": 0,
  "errmsg": "ok"
}
Demo 实现(云函数版,推荐)
  1. /msgSecCheck/index.js
javascript 复制代码
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })

exports.main = async (event) => {
  const { content } = event

  try {
    const result = await cloud.openapi.security.msgSecCheck({
      content: content,
      version: 2,
      scene: 2
    })

    return {
      code: 0,
      data: result
    }
  } catch (err) {
    return {
      code: -1,
      msg: err.errMsg
    }
  }
}
  1. 云函数 config.json
javascript 复制代码
{
  "permissions": {
    "openapi": ["security.msgSecCheck"]
  }
}
  1. 小程序端调用
javascript 复制代码
wx.cloud.callFunction({
  name: 'msgSecCheck',
  data: {
    content: '需要检测的文本'
  }
}).then(res => {
  console.log(res.result)
})
Demo实现(原生)
  1. token.js
javascript 复制代码
// 微信小程序原生写法:无感刷新 access_token
let accessToken = ''
let expireTime = 0
let isRefreshing = false
let requests = []

const getUGCToken = async () => {
  return new Promise((resolve, reject) => {
    const now = Date.now()

    // 1. 如果 token 有效,直接返回
    if (accessToken && now < expireTime) {
      resolve(accessToken)
      return
    }

    // 2. 防止重复刷新
    if (isRefreshing) {
      requests.push(() => resolve(accessToken))
      return
    }

    isRefreshing = true

    // 3. 原生 wx.request 获取 token
    const appid = '你的appid'
    const secret = '你的secret'

    wx.request({
      url: 'https://api.weixin.qq.com/cgi-bin/token',
      method: 'GET',
      data: {
        grant_type: 'client_credential',
        appid: appid,
        secret: secret
      },
      success: (res) => {
        const data = res.data
        if (data.access_token) {
          accessToken = data.access_token
          expireTime = now + (data.expires_in - 60) * 1000

          // 执行等待中的请求
          requests.forEach((cb) => cb(accessToken))
          requests = []
          resolve(accessToken)
        } else {
          reject(data.errmsg || '获取token失败')
        }
      },
      fail: (err) => {
        reject(err)
      },
      complete: () => {
        isRefreshing = false
      }
    })
  })
}
// 文本安全检测
async function msgSecCheck(content) {
  const token = await getUGCToken()
  const openid = wx.getStorageSync('openId')

  return new Promise((resolve, reject) => {
    wx.request({
      url: `https://api.weixin.qq.com/wxa/msg_sec_check?access_token=${token}`,
      method: 'POST',
      header: {
        'Content-Type': 'application/json'
      },
      data: {
        openid: openid,
        content: content,
        version: 2,
        scene: 2
      },
      success(res) {
        const data = res.data
        // errcode 0 成功
        // 违规会返回 87014 等
        resolve(data)
      },
      fail(err) {
        reject(err)
      }
    })
  })
}
module.exports = {
  getUGCToken,
  msgSecCheck
}
  • 使用
javascript 复制代码
try {
   const result = await msgSecCheck(this.data.wish)
   if (result.errcode === 0) {
     // 通过
     // wx.showToast({ title: '内容正常', icon: 'success' })
   } else {
     // 违规/风险
     wx.showToast({ title: result.errmsg || '内容违规', icon: 'none' })
     return
   }
 } catch (err) {
   console.error(err)
   wx.showToast({ title: '检测失败', icon: 'none' })
 }

二、media_check_async

mediaCheckAsync 是图片 / 音频异步安全检测,用于检测图片是否违规(涉政、色情、敏感等)。

接口地址:POST https://api.weixin.qq.com/wxa/media_check_async?access_token=TOKEN

  • 支持:图片(网络 URL)
  • 方式:异步检测(结果通过 回调 / 事件 推送)
  • scene 场景:
    • 1 用户资料
    • 2 评论 / 许愿 / 留言(用的这个)
    • 3 帖子
    • 4 其他
javascript 复制代码
// 微信小程序原生写法:无感刷新 access_token
let accessToken = ''
let expireTime = 0
let isRefreshing = false
let requests = []

const getUGCToken = async () => {
  return new Promise((resolve, reject) => {
    const now = Date.now()

    // 1. 如果 token 有效,直接返回
    if (accessToken && now < expireTime) {
      resolve(accessToken)
      return
    }

    // 2. 防止重复刷新
    if (isRefreshing) {
      requests.push(() => resolve(accessToken))
      return
    }

    isRefreshing = true

    // 3. 原生 wx.request 获取 token
    const appid = 'appid '
    const secret = 'secret '

    wx.request({
      url: 'https://api.weixin.qq.com/cgi-bin/token',
      method: 'GET',
      data: {
        grant_type: 'client_credential',
        appid: appid,
        secret: secret
      },
      success: (res) => {
        const data = res.data
        if (data.access_token) {
          accessToken = data.access_token
          expireTime = now + (data.expires_in - 60) * 1000

          // 执行等待中的请求
          requests.forEach((cb) => cb(accessToken))
          requests = []
          resolve(accessToken)
        } else {
          reject(data.errmsg || '获取token失败')
        }
      },
      fail: (err) => {
        reject(err)
      },
      complete: () => {
        isRefreshing = false
      }
    })
  })
}
// 文本安全检测
async function msgSecCheck(content) {
  const token = await getUGCToken()
  const openid = wx.getStorageSync('openId')

  return new Promise((resolve, reject) => {
    wx.request({
      url: `https://api.weixin.qq.com/wxa/msg_sec_check?access_token=${token}`,
      method: 'POST',
      header: {
        'Content-Type': 'application/json'
      },
      data: {
        openid: openid,
        content: content,
        version: 2,
        scene: 2
      },
      success(res) {
        const data = res.data
        // errcode 0 成功
        // 违规会返回 87014 等
        resolve(data)
      },
      fail(err) {
        reject(err)
      }
    })
  })
}
/**
 * 图片异步安全检测
 * @param {String} media_url 图片网络地址(必须公网可访问)
 * @param {String} openid 用户openid
 */
async function mediaCheckAsync(media_url, openid) {
  const token = await getUGCToken()
  const openid = wx.getStorageSync('openId')

  return new Promise((resolve, reject) => {
    wx.request({
      url: `https://api.weixin.qq.com/wxa/media_check_async?access_token=${token}`,
      method: 'POST',
      header: {
        'Content-Type': 'application/json'
      },
      data: {
        media_url: media_url,
        media_type: 2,        // 1=音频 2=图片
        version: 2,           // 固定2
        scene: 2,             // 2=评论/许愿/留言
        openid: openid        // 必填
      },
      success(res) {
        resolve(res.data)
      },
      fail(err) {
        reject(err)
      }
    })
  })
}


module.exports = {
  getUGCToken,
  msgSecCheck,
  mediaCheckAsync
}
  • 使用
javascript 复制代码
const { mediaCheckAsync } = require('../../utils/imageCheck')

Page({
  // 选择图片 + 检测
  async chooseAndCheckImage() {
    wx.chooseMedia({
      count: 1,
      mediaType: ['image'],
      success: async (res) => {
        const filePath = res.tempFiles[0].tempFilePath

        // 1. 上传到你的服务器获得 网络URL
        // 这里必须是 https 公网地址
        // const onlineUrl = await 你的上传接口(filePath)

        // 示例(替换成你真实的图片地址)
        const onlineUrl = 'https://pic.baidu.com/xxx.jpg'
        const openid = wx.getStorageSync('openid')

        // 2. 图片安全检测
        const result = await mediaCheckAsync(onlineUrl, openid)
        console.log('图片检测结果:', result)

        if (result.errcode === 0) {
          wx.showToast({ title: '图片已提交检测,等待结果' })
        } else {
          wx.showToast({ title: '图片违规', icon: 'none' })
        }
      }
    })
  }
})
相关推荐
tntxia1 天前
网络安全漏洞修复(一)
安全
泯泷3 天前
第 2 篇:设计第一套字节码:Opcode、Instruction 与 Constant Pool
前端·javascript·安全
泯泷3 天前
第 1 篇:从 1 + 2 开始:亲手写出第一台 JSVM
前端·javascript·安全
Flynt7 天前
npm v12 来了:allowScripts 默认关闭,我的项目差点跑不起来
安全·npm·node.js
冬奇Lab12 天前
Skill 系列(02):Skill 安全风险——三类攻击面的实战测试
人工智能·安全·开源
Aphasia31115 天前
VPN 与内网穿透
安全
Mr_愚人派16 天前
当"Claude"不再是 Claude:一次第三方 API 代理引发的 AI 身份伪造排查实录
人工智能·安全
m0_5261194017 天前
iconfont我修改好颜色,但是在小程序项目是黑色的
小程序
DaLi Yao17 天前
【无标题】
人工智能·安全
Alsn8617 天前
等待学习-学习目录:Docker 容器安全攻防
学习·安全·docker