security.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. package security
  2. import (
  3. context2 "context"
  4. "fmt"
  5. "strconv"
  6. "github.com/silenceper/wechat/v2/miniprogram/context"
  7. "github.com/silenceper/wechat/v2/util"
  8. )
  9. const (
  10. mediaCheckAsyncURL = "https://api.weixin.qq.com/wxa/media_check_async?access_token=%s"
  11. imageCheckURL = "https://api.weixin.qq.com/wxa/img_sec_check?access_token=%s"
  12. msgCheckURL = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=%s"
  13. )
  14. // Security 内容安全
  15. type Security struct {
  16. *context.Context
  17. }
  18. // NewSecurity init
  19. func NewSecurity(ctx *context.Context) *Security {
  20. return &Security{ctx}
  21. }
  22. // MediaCheckAsyncV1Request 图片/音频异步校验请求参数
  23. type MediaCheckAsyncV1Request struct {
  24. MediaURL string `json:"media_url"` // 要检测的图片或音频的url,支持图片格式包括jpg, jepg, png, bmp, gif(取首帧),支持的音频格式包括mp3, aac, ac3, wma, flac, vorbis, opus, wav
  25. MediaType uint8 `json:"media_type"` // 1:音频;2:图片
  26. }
  27. // MediaCheckAsyncV1 异步校验图片/音频是否含有违法违规内容
  28. // Deprecated
  29. // 在2021年9月1日停止更新,请尽快更新至 2.0 接口。建议使用 MediaCheckAsync
  30. func (security *Security) MediaCheckAsyncV1(in *MediaCheckAsyncV1Request) (traceID string, err error) {
  31. accessToken, err := security.GetAccessToken()
  32. if err != nil {
  33. return
  34. }
  35. uri := fmt.Sprintf(mediaCheckAsyncURL, accessToken)
  36. response, err := util.PostJSON(uri, in)
  37. if err != nil {
  38. return
  39. }
  40. // 使用通用方法返回错误
  41. var res struct {
  42. util.CommonError
  43. TraceID string `json:"trace_id"`
  44. }
  45. err = util.DecodeWithError(response, &res, "MediaCheckAsyncV1")
  46. return res.TraceID, err
  47. }
  48. // MediaCheckAsyncRequest 图片/音频异步校验请求参数
  49. type MediaCheckAsyncRequest struct {
  50. MediaURL string `json:"media_url"` // 要检测的图片或音频的url,支持图片格式包括jpg, jepg, png, bmp, gif(取首帧),支持的音频格式包括mp3, aac, ac3, wma, flac, vorbis, opus, wav
  51. MediaType uint8 `json:"media_type"` // 1:音频;2:图片
  52. OpenID string `json:"openid"` // 用户的openid(用户需在近两小时访问过小程序)
  53. Scene uint8 `json:"scene"` // 场景枚举值(1 资料;2 评论;3 论坛;4 社交日志)
  54. }
  55. // MediaCheckAsync 异步校验图片/音频是否含有违法违规内容
  56. func (security *Security) MediaCheckAsync(in *MediaCheckAsyncRequest) (traceID string, err error) {
  57. return security.MediaCheckAsyncContext(context2.Background(), in)
  58. }
  59. // MediaCheckAsyncContext 异步校验图片/音频是否含有违法违规内容
  60. func (security *Security) MediaCheckAsyncContext(ctx context2.Context, in *MediaCheckAsyncRequest) (traceID string, err error) {
  61. accessToken, err := security.GetAccessTokenContext(ctx)
  62. if err != nil {
  63. return
  64. }
  65. var req struct {
  66. MediaCheckAsyncRequest
  67. Version uint `json:"version"` // 接口版本号,2.0版本为固定值2
  68. }
  69. req.MediaCheckAsyncRequest = *in
  70. req.Version = 2
  71. uri := fmt.Sprintf(mediaCheckAsyncURL, accessToken)
  72. response, err := util.PostJSONContext(ctx, uri, req)
  73. if err != nil {
  74. return
  75. }
  76. // 使用通用方法返回错误
  77. var res struct {
  78. util.CommonError
  79. TraceID string `json:"trace_id"`
  80. }
  81. err = util.DecodeWithError(response, &res, "MediaCheckAsync")
  82. return res.TraceID, err
  83. }
  84. // ImageCheckV1 校验一张图片是否含有违法违规内容(同步)
  85. // https://developers.weixin.qq.com/miniprogram/dev/framework/security.imgSecCheck.html
  86. // Deprecated
  87. // 在2021年9月1日停止更新。建议使用 MediaCheckAsync
  88. func (security *Security) ImageCheckV1(filename string) (err error) {
  89. accessToken, err := security.GetAccessToken()
  90. if err != nil {
  91. return
  92. }
  93. uri := fmt.Sprintf(imageCheckURL, accessToken)
  94. response, err := util.PostFile("media", filename, uri)
  95. if err != nil {
  96. return
  97. }
  98. // 使用通用方法返回错误
  99. return util.DecodeWithCommonError(response, "ImageCheckV1")
  100. }
  101. // CheckSuggest 检查建议
  102. type CheckSuggest string
  103. const (
  104. // CheckSuggestRisky 违规风险建议
  105. CheckSuggestRisky CheckSuggest = "risky"
  106. // CheckSuggestPass 安全
  107. CheckSuggestPass CheckSuggest = "pass"
  108. // CheckSuggestReview 需要审查
  109. CheckSuggestReview CheckSuggest = "review"
  110. )
  111. // MsgScene 文本场景
  112. type MsgScene uint8
  113. const (
  114. // MsgSceneMaterial 资料文件检查场景
  115. MsgSceneMaterial MsgScene = iota + 1
  116. // MsgSceneComment 评论
  117. MsgSceneComment
  118. // MsgSceneForum 论坛
  119. MsgSceneForum
  120. // MsgSceneSocialLog 社交日志
  121. MsgSceneSocialLog
  122. )
  123. // CheckLabel 检查命中标签
  124. type CheckLabel int
  125. func (cl CheckLabel) String() string {
  126. switch cl {
  127. case 100:
  128. return "正常"
  129. case 10001:
  130. return "广告"
  131. case 20001:
  132. return "时政"
  133. case 20002:
  134. return "色情"
  135. case 20003:
  136. return "辱骂"
  137. case 20006:
  138. return "违法犯罪"
  139. case 20008:
  140. return "欺诈"
  141. case 20012:
  142. return "低俗"
  143. case 20013:
  144. return "版权"
  145. case 21000:
  146. return "其他"
  147. default:
  148. return strconv.Itoa(int(cl))
  149. }
  150. }
  151. // MsgCheckRequest 文本检查请求
  152. type MsgCheckRequest struct {
  153. OpenID string `json:"openid"` // 用户的openid(用户需在近两小时访问过小程序)
  154. Scene MsgScene `json:"scene"` // 场景枚举值(1 资料;2 评论;3 论坛;4 社交日志)
  155. Content string `json:"content"` // 需检测的文本内容,文本字数的上限为 2500 字,需使用 UTF-8 编码
  156. Nickname string `json:"nickname"` // (非必填)用户昵称,需使用UTF-8编码
  157. Title string `json:"title"` // (非必填)文本标题,需使用UTF-8编码
  158. Signature string `json:"signature"` // (非必填)个性签名,该参数仅在资料类场景有效(scene=1),需使用UTF-8编码
  159. }
  160. // MsgCheckResponse 文本检查响应
  161. type MsgCheckResponse struct {
  162. util.CommonError
  163. TraceID string `json:"trace_id"` // 唯一请求标识
  164. Result struct {
  165. Suggest CheckSuggest `json:"suggest"` // 建议
  166. Label CheckLabel `json:"label"` // 命中标签
  167. } `json:"result"` // 综合结果
  168. Detail []struct {
  169. ErrCode int64 `json:"errcode"` // 错误码,仅当该值为0时,该项结果有效
  170. Strategy string `json:"strategy"` // 策略类型
  171. Suggest string `json:"suggest"` // 建议
  172. Label CheckLabel `json:"label"` // 命中标签
  173. Prob uint `json:"prob"` // 置信度。0-100,越高代表越有可能属于当前返回的标签(label)
  174. Keyword string `json:"keyword"` // 命中的自定义关键词
  175. } `json:"detail"` // 详细检测结果
  176. }
  177. // MsgCheckV1 检查一段文本是否含有违法违规内容
  178. // Deprecated
  179. // 在2021年9月1日停止更新,请尽快更新至 2.0 接口。建议使用 MsgCheck
  180. func (security *Security) MsgCheckV1(content string) (res MsgCheckResponse, err error) {
  181. accessToken, err := security.GetAccessToken()
  182. if err != nil {
  183. return
  184. }
  185. var req struct {
  186. Content string `json:"content"`
  187. }
  188. req.Content = content
  189. uri := fmt.Sprintf(msgCheckURL, accessToken)
  190. response, err := util.PostJSON(uri, req)
  191. if err != nil {
  192. return
  193. }
  194. // 使用通用方法返回错误
  195. err = util.DecodeWithError(response, &res, "security.MsgCheckV1")
  196. return
  197. }
  198. // MsgCheck 检查一段文本是否含有违法违规内容
  199. func (security *Security) MsgCheck(in *MsgCheckRequest) (res MsgCheckResponse, err error) {
  200. return security.MsgCheckContext(context2.Background(), in)
  201. }
  202. // MsgCheckContext 检查一段文本是否含有违法违规内容
  203. func (security *Security) MsgCheckContext(ctx context2.Context, in *MsgCheckRequest) (res MsgCheckResponse, err error) {
  204. accessToken, err := security.GetAccessTokenContext(ctx)
  205. if err != nil {
  206. return
  207. }
  208. var req struct {
  209. MsgCheckRequest
  210. Version uint `json:"version"`
  211. }
  212. req.MsgCheckRequest = *in
  213. req.Version = 2
  214. uri := fmt.Sprintf(msgCheckURL, accessToken)
  215. response, err := util.PostJSONContext(ctx, uri, req)
  216. if err != nil {
  217. return
  218. }
  219. // 使用通用方法返回错误
  220. err = util.DecodeWithError(response, &res, "security.MsgCheck")
  221. return
  222. }