first commit
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"sundynix-go/global"
|
||||
"sundynix-go/pkg/httpclient"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// GetMiniAccessToken 获取小程序的access_token
|
||||
func GetMiniAccessToken() string {
|
||||
ak, err := global.Redis.Get(context.Background(), "zeeq_mini_access_token").Result()
|
||||
if errors.Is(err, redis.Nil) {
|
||||
// 从微信服务器获取
|
||||
//重新从微信服务器获取
|
||||
url := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + global.Config.MiniProgram.AppId + "&secret=" + global.Config.MiniProgram.AppSecret
|
||||
myHttpClient := httpclient.GetClient()
|
||||
resp, err := myHttpClient.Get(url)
|
||||
if err != nil {
|
||||
log.Fatalf("Error making GET request: %s", err)
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
if err != nil {
|
||||
log.Fatalf("Error closing response body: %s", err)
|
||||
}
|
||||
}(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading response body: %s", err)
|
||||
}
|
||||
res := string(body)
|
||||
|
||||
var data map[string]interface{}
|
||||
err = json.Unmarshal([]byte(res), &data)
|
||||
if err != nil {
|
||||
log.Fatalf("Error unmarshalling JSON: %s", err)
|
||||
}
|
||||
ak = data["access_token"].(string)
|
||||
ex := data["expires_in"].(float64)
|
||||
global.Redis.Set(context.Background(), "zeeq_mini_access_token", ak, time.Duration(ex)*time.Second) //秒
|
||||
} else if err != nil {
|
||||
log.Fatalf("Error getting access token from Redis: %s", err)
|
||||
}
|
||||
return ak
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sundynix-go/global"
|
||||
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/utils"
|
||||
)
|
||||
|
||||
// GetWxPayClient 初始化微信支付客户端
|
||||
func GetWxPayClient() (*core.Client, error) {
|
||||
|
||||
//2.加载私钥
|
||||
mchPrivateKey, err := utils.LoadPrivateKeyWithPath(global.Config.WechatPay.PrivateKeyPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mchPublicKey, err := utils.LoadPublicKeyWithPath(global.Config.WechatPay.PublicKeyPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx := context.Background()
|
||||
// 3. 创建客户端配置 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力
|
||||
opts := []core.ClientOption{
|
||||
option.WithWechatPayPublicKeyAuthCipher(global.Config.WechatPay.MchId,
|
||||
global.Config.WechatPay.MchCertificateSerialNumber,
|
||||
mchPrivateKey, global.Config.WechatPay.PublicKeyId, mchPublicKey), // 自动处理签名/验签
|
||||
}
|
||||
client, err := core.NewClient(ctx, opts...)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("new wechat pay client err:%s", err)
|
||||
}
|
||||
return client, err
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sundynix-go/global"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// WeChatCommonResponse 微信通用响应
|
||||
type WeChatCommonResponse struct {
|
||||
Errcode int `json:"errcode"`
|
||||
Errmsg string `json:"errmsg"`
|
||||
}
|
||||
|
||||
// MsgSecCheckDetail 文本检测结果详情
|
||||
type MsgSecCheckDetail struct {
|
||||
Strategy string `json:"strategy"`
|
||||
Errcode int `json:"errcode"`
|
||||
Suggest string `json:"suggest"`
|
||||
Label int `json:"label"`
|
||||
Prob int `json:"prob"`
|
||||
}
|
||||
|
||||
// MsgSecCheckResult 文本检测结果
|
||||
type MsgSecCheckResult struct {
|
||||
Suggest string `json:"suggest"`
|
||||
Label int `json:"label"`
|
||||
}
|
||||
|
||||
// MsgSecCheckResponse 文本检测响应
|
||||
type MsgSecCheckResponse struct {
|
||||
WeChatCommonResponse
|
||||
Result MsgSecCheckResult `json:"result"`
|
||||
Detail []MsgSecCheckDetail `json:"detail"`
|
||||
}
|
||||
|
||||
// MediaCheckAsyncResponse 媒体检测异步响应
|
||||
type MediaCheckAsyncResponse struct {
|
||||
WeChatCommonResponse
|
||||
TraceId string `json:"trace_id"`
|
||||
}
|
||||
|
||||
// MsgSecCheck 文本内容安全识别
|
||||
// content: 需检测的文本内容
|
||||
// openid: 用户的openid(用户需在近两小时访问过小程序)
|
||||
// return: true-通过, false-不通过
|
||||
func MsgSecCheck(content string, openid string) bool {
|
||||
// 2024-05-15: 微信api调整
|
||||
// https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/sec-center/sec-check/msgSecCheck.html
|
||||
accessToken := GetMiniAccessToken()
|
||||
url := "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=" + accessToken
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"version": 2,
|
||||
"openid": openid,
|
||||
"scene": 2, // 2-资料说明
|
||||
"content": content,
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
global.Logger.Error("MsgSecCheck json marshal error", zap.Error(err))
|
||||
return false
|
||||
}
|
||||
|
||||
resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
global.Logger.Error("MsgSecCheck http post error", zap.Error(err))
|
||||
return false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
global.Logger.Error("MsgSecCheck read body error", zap.Error(err))
|
||||
return false
|
||||
}
|
||||
|
||||
var response MsgSecCheckResponse
|
||||
if err := json.Unmarshal(body, &response); err != nil {
|
||||
global.Logger.Error("MsgSecCheck json unmarshal error", zap.Error(err))
|
||||
return false
|
||||
}
|
||||
|
||||
if response.Errcode != 0 {
|
||||
global.Logger.Error("MsgSecCheck api error", zap.Int("errcode", response.Errcode), zap.String("errmsg", response.Errmsg))
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查 result.suggest
|
||||
if response.Result.Suggest == "pass" {
|
||||
return true
|
||||
}
|
||||
|
||||
global.Logger.Warn("MsgSecCheck risky content",
|
||||
zap.String("content", content),
|
||||
zap.String("suggest", response.Result.Suggest),
|
||||
zap.Int("label", response.Result.Label),
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
// MediaCheckAsync 多媒体内容安全识别(异步)
|
||||
// mediaUrl: 需检测的多媒体url
|
||||
// mediaType: 1:音频; 2:图片
|
||||
// openid: 用户的openid
|
||||
// return: trace_id, error
|
||||
func MediaCheckAsync(mediaUrl string, mediaType int, openid string) (string, error) {
|
||||
accessToken := GetMiniAccessToken()
|
||||
url := "https://api.weixin.qq.com/wxa/media_check_async?access_token=" + accessToken
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"media_url": mediaUrl,
|
||||
"media_type": mediaType,
|
||||
"version": 2,
|
||||
"openid": openid,
|
||||
"scene": 2,
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var response MediaCheckAsyncResponse
|
||||
if err := json.Unmarshal(body, &response); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if response.Errcode != 0 {
|
||||
global.Logger.Error("MediaCheckAsync api error", zap.Int("errcode", response.Errcode), zap.String("errmsg", response.Errmsg))
|
||||
return "", fmt.Errorf("errcode: %d, errmsg: %s", response.Errcode, response.Errmsg)
|
||||
}
|
||||
|
||||
if response.TraceId != "" {
|
||||
return response.TraceId, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("no trace_id returned")
|
||||
}
|
||||
Reference in New Issue
Block a user