个人案例
- 小程序图片安全审核方案与security.imgSecCheck不能校验超过1M图片的解决思路
背景需求:我个人做了一款校友交流的小程序。里面有校友相册,校友聚会,校友资讯,校友互助等功能,校友从本地相册选一张或者多张图片后,连同文章内容保存到服务器。这里就涉及到内容安全了,提交审核没有通过也是因为这个没有做内容安全。防止一些色情低俗的事情发生。 [图片] 当前可用的图片审核方案的优缺点:方案1 :小程序自带的同步同步API:security.imgSecCheck优点:小程序自带,无须额外申请,格式支持PNG、JPEG、JPG、GIF,单个 appId 调用上限为 2000 次/分钟,200,000 次/天,基本满足需要 缺点:图片大小限制1M ,图片尺寸不超过 750px x 1334px 虽然有图片尺寸限制,但是在实际应用中发现,尺寸到4000 x 4000都可以,但是4000以上会出现问题 方案2 :小程序自带的异步API: security.mediaCheckAsync优点:单个文件大小不超过10M,解决手机拍照或者相册里的大图片限制 缺点:属于异步调用,必须先上传图片,处理不及时,最多可能30分钟才返回结果,需要提供回调URL来接受处理结果,不健康的图片无法实时处理,容易造成风险 方案3: 小程序服务市场的珊瑚图片安全优点:非常好用,但是已经下架(2021年4月9日),无比郁闷 [图片] 方案4: 小程序服务市场的天御才上线没多久,按官方给出的文档无法正常调用成功,而且只有30天的免费使用时长 [图片] 方案5 :腾讯云:T-Sec 天御 图片内容安全 优点:能精准识别图片中出现可能令人反感、不安全或不适宜内容,支持配置图片黑名单,识别自定义的图片类型。 缺点:文档调用复杂,价格高昂 [图片] 方案6 :百度云:内容审核平台 优点:基于深度学习的智能内容审核方案,准确过滤图像和视频中的色情、暴恐、政治敏感、广告、恶心、不良场景等违规内容,也能从美观、 清晰等维度对图像进行筛选,紧贴业务需求,释放审核人力 缺点:1)还是价格!!!2)接入成本 我的解决思路综合上述方案优缺点,我还是选择方案1(security.imgSecCheck),原因如下 1 小程序自带的API,调用方便,尤其是云函数调用方便 2 没有额外的申请流程 3 没有费用开销 4 量度次数上限基本满足我的校友录小程序需求 security.imgSecCheck 亟待解决的问题:1. 图片大小限制1M 2. 图片尺寸限制的问题(官方表述750px x 1334px) 我的解决方案虽然官方文档有些图片尺寸的上限,这也是当时我犹豫不决的原因, 但是在实际应用中发现,尺寸到4000 x 4000都可以实现检测,但是4000px以上会出现问题, 实际图片中出现上述大尺寸的少,所以可以暂且忽略, 只需要针对图片大于1M的进行压缩处理 大于1M的图片 思路:校友会小程序相册选图片 --> 判断图片是否大于1M --> 压缩图片 --> 上传图片流给security.imgSecCheck检测-->通过-->保存 小于1M的图片 思路:校友会小程序相册选图片 --> 判断图片是否大于1M --> 不压缩图片 --> 上传图片流给security.imgSecCheck检测-->通过-->保存 [图片] 代码实现:小程序端/** * 选择上传图片 */ bindChooseImgTap: function (e) { wx.chooseImage({ count: this.data.imgMax - this.data.imgList.length, //默认9 sizeType: ['compressed'], //可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], //从相册选择 success: async (res) => { wx.showLoading({ title: '图片校验中', mask: true }); for (let k = 0; k < res.tempFiles.length; k++) { let size = res.tempFiles[k].size; let path = res.tempFiles[k].path; if (!contentCheckHelper.imgTypeCheck(path)) { wx.hideLoading(); return pageHelper.showNoneToast('只能上传png、jpg、jpeg格式', 3000); } let imageMaxSize = 1024 * 1000 * this.data.imgUploadSize; console.log('IMG SIZE=' + size + ',' + size / 1024 + 'K'); if (!contentCheckHelper.imgSizeCheck(size, imageMaxSize)) { wx.hideLoading(); return pageHelper.showNoneToast('单张图片大小不能超过 ' + this.data.imgUploadSize + 'M', 3000); } // 图片校验 if (this.data.isCheck) { let that = this; let callback = async function (path) { let check = await contentCheckHelper.imgCheckCloud(path); if (!check) { wx.hideLoading(); return false; //return pageHelper.showNoneToast('存在不合适的图片, 已屏蔽', 3000); } that.setData({ imgList: that.data.imgList.concat(path) }); that.triggerEvent('myImgUploadEvent', that.data.imgList); return true; } // 图片大于1M,压缩 if (size > 1000 * 1000) { wx.compressImage({ src: path, // 图片路径 quality: 50, // 压缩质量 fail: function () { pageHelper.showModal('上传失败,请重新上传'); }, success: async function (res) { await callback(res.tempFilePath); } }); } else { // 小于1M,不压缩 if (!await callback(path)) return; } } else { //图片无须审核 this.setData({ imgList: this.data.imgList.concat(path) }); this.triggerEvent('myImgUploadEvent', this.data.imgList); } } wx.hideLoading(); } }); }, 云端async function checkImg(imgData, mine) { // 下载CDN图片进行检查 const axios = require('axios'); let buffer = null; await axios({ method: 'get', url: imgData, responseType: 'arraybuffer' }).then(res => { buffer = res.data; }); console.log('buffer SIZE=' + buffer.length / 1024 + 'K'); let cloud = cloudBase.getCloud(); try { const result = await cloud.openapi.security.imgSecCheck({ media: { contentType: 'image/png', value: buffer //value: Buffer.from(imgData, 'base64') // 这里必须要将小程序端传过来的进行Buffer转化,否则就会报错,接口异常 } }); console.log('imgcheck', result); if (!result || result.errCode !== 0) throw new AppError('图片内容不合适,请修改'); } catch (err) { console.log('imgcheck ex', err); if (err.errMsg && err.errMsg.includes('invalid media size')) throw new AppError('图片过大,请修改'); else if (err.errMsg && err.errMsg.includes('content size out of limit')) throw new AppError('图片尺寸过大,请修改'); else if (err.errMsg && err.errMsg.includes('604102')) throw new AppError('图片过大,请上传较小图片'); else throw new AppError('图片内容不合适,请修改'); } } 测试情况:校友会小程序中上传正常图片不含违法违规,测试50次,全部通过。校友会小程序上线后暂无发现检测失败情况。 [图片]
2021-07-12 - 基于微信小程序的校友录(校友会)建设整体方案
背景 主要面向毕业后在某城市工作的校友,给大家构建一个充分交流的平台,“人脉”积累是本软件的功能特色。通过校友身份这个共同的纽带,为自己的人生道路积累持续的人脉。 功能规划 1)对于校友录建设者而言,利用本产品均能够在最短的时间内,花费最低的费用,采用最少的人力,架设一个性能优异、功能全面、安全稳定的校友人脉交流平台。同时可以在后台方便的管理整个校友网站,个性化的定义网站模板和各项属性。 2) 对于使用的校友而言,将能方便、快捷地享受到校友录带来的互动体验、发表校友供需,求职招聘等互助信息,发表相册、发起/报名参与校友活动、创建群助手、添加/修改资料、查找/搜索校友信息,站内消息等。 技术路线 一个采用微信小程序和腾讯云开发技术构建的高效校友录解决方案。使用腾讯云开发技术,免费资源配额,无需域名和服务器即可搭建 小程序在微信里打开,无须下载app,也无须再访问传统的PC站点,随时随地可以和互动 用户系统功能示意图[图片] 主要功能截图[图片][图片][图片] [图片][图片][图片] [图片]
2020-11-23 - 校友录小程序(校友会)后台解决方案
5G时代,讲究效率, 因此摒弃了传统的PC端管理后台,特地研发了小程序端后台管理系统。 可以通过手机小程序,随时随地的管理您的校友录数据,审核用户,发布新资讯等。 对于要求比较高的数据管理,比如复杂的文章内容,图片上传等,亦可以通过PC端微信的里的小程序,在PC电脑上进行管理。 两种方式方便随时对校友录程序的管理。 后台管理系统功能示意图[图片] 各功能模块截图: [图片][图片][图片] [图片][图片][图片] [图片][图片][图片] [图片][图片][图片] [图片]
2020-11-23 - CC校友录小程序云开发的安装部署
CC校友录结合移动互联网时代,独家引入微信小程序形式,创造全天候的用户体验。 主要面向毕业后在某城市工作的校友,给大家构建一个充分交流的平台,“人脉”积累是本软件的功能特色,通过校友身份这个共同的纽带,为自己的人生道路积累持续的人脉。 特点无广告:本项目希望通过微信小程序,构建一款无广告,真实可靠的毕业校友通讯录。 简约:只做最基础功能,不臃肿,主打内容极简,功能简洁直击痛点 安全:保护校友的信息安全,隐私内容需要申请后可见。 方便:上传自己的个人信息,方便在需要时取得联系。小程序无需下载APP随用随走。 技术使用项目使用微信小程序平台进行开发。 使用腾讯云开发技术,免费资源配额, 无需域名和服务器即可搭建。 小程序本身的即用即走,适合小工具的使用场景,也适合程序的开发。 项目效果截图[图片] [图片] [图片] [图片] [图片] [图片] 部署教程:1 源码解压2 在微信小程序开发工具中导入 解压后的文件夹[图片] 3 开通云开发环境参考微信官方文档:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html 4 数据库操作建立数据库集合 t_user t_album t_info t_setup 5 云函数及配置本项目使用到了一个云函数cloud 在云函数cloudfunctions文件夹下选择一个云函数cloud , 右键选择在终端中打开,然后执行 npm install –product [图片] 打开cloudfunctions/cloud/comm/config.js文件,配置环境ID [图片] 6 客户端配置打开miniprogram/helper/setting.js文件,配置环境ID [图片] 7 内容安全腾讯对小程序有严格的审核机制,每个小程序都要接入内容安全校验, 打开https://developers.weixin.qq.com/community/servicemarket/detail/000a246b6fca70b76a896e6a25ec15 页面,点击购买(实际免费) [图片] 至此完全配置完毕。 在线演示:[图片]
2020-11-22