| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- package wechat
- import (
- "context"
- "crypto/md5"
- "dsbqj-admin/pkg/cache"
- "dsbqj-admin/pkg/logger"
- "dsbqj-admin/pkg/util"
- "encoding/hex"
- "fmt"
- "github.com/goccy/go-json"
- "github.com/silenceper/wechat"
- wechatCtx "github.com/silenceper/wechat/context"
- "os"
- "sort"
- "strconv"
- "strings"
- "sync/atomic"
- "time"
- wechatCache "dsbqj-admin/pkg/cache/wechat"
- )
- var GOpenid OpenidMgr
- type OpenidMgr struct {
- V atomic.Value //值
- Over int64 //过期时间
- }
- type WechatHelper struct {
- ctx context.Context
- Wechat *wechat.Wechat
- AppId string
- AppSecret string
- }
- const (
- subscribeUrl = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="
- accessTokenURL = "http://fx.wumiao666.com/cp/getaccesstoken"
- )
- type SignResult struct {
- Param string
- Line string
- Sign string
- }
- func AppSign(params map[string]string, key string) SignResult {
- var builder strings.Builder
- // 1. 排序 key
- keys := make([]string, 0, len(params))
- for k := range params {
- keys = append(keys, k)
- }
- sort.Strings(keys)
- // 2. 拼接 key=value&
- for _, k := range keys {
- builder.WriteString(k)
- builder.WriteString("=")
- builder.WriteString(params[k])
- builder.WriteString("&")
- }
- strForWX := builder.String()
- str := strings.TrimSuffix(strForWX, "&")
- line := str + key
- sign := md5Hex(line)
- return SignResult{
- Param: str,
- Line: line,
- Sign: strings.ToLower(sign),
- }
- }
- func md5Hex(s string) string {
- sum := md5.Sum([]byte(s))
- return hex.EncodeToString(sum[:])
- }
- type TokenData struct {
- AccessToken string `json:"accessToken"`
- ExpiresSecond *int64 `json:"expiresSecond"`
- }
- type ResAccessToken struct {
- Msg string `json:"msg"`
- Code string `json:"code"`
- Data *TokenData `json:"data"`
- }
- func GetAccessTokenFromServer(ctx *wechatCtx.Context) (resAccessToken ResAccessToken, err error) {
- var params = map[string]string{}
- params["platformId"] = os.Getenv("SDK_PLATFORMID")
- params["appId"] = os.Getenv("SDK_APPID")
- params["wxAppId"] = os.Getenv("WECHAT_APPID")
- params["clearCache"] = os.Getenv("SDK_CLEARCACHE")
- params["requestTime"] = strconv.Itoa(int(util.GetNowSecond()))
- res := AppSign(params, os.Getenv("SDK_APPKEY"))
- url := fmt.Sprintf("%s?%s&sign=%s", accessTokenURL, res.Param, res.Sign)
- var body []byte
- body, err = util.HTTPGet(url)
- if err != nil {
- return
- }
- err = json.Unmarshal(body, &resAccessToken)
- if err != nil {
- return
- }
- if resAccessToken.Code != "0" {
- err = fmt.Errorf("get access_token error : errcode=%v , errormsg=%v", resAccessToken.Msg)
- return
- }
- accessTokenCacheKey := fmt.Sprintf("access_token_%s", ctx.AppID)
- var expires int64 = 600
- if resAccessToken.Data.ExpiresSecond != nil {
- expires = *resAccessToken.Data.ExpiresSecond
- }
- err = ctx.Cache.Set(accessTokenCacheKey, resAccessToken.Data.AccessToken, time.Duration(expires)*time.Second)
- return
- }
- func MyAccessTokenFunc(ctx *wechatCtx.Context) (accessToken string, err error) {
- accessTokenCacheKey := fmt.Sprintf("access_token_%s", ctx.AppID)
- val := ctx.Cache.Get(accessTokenCacheKey)
- if val != nil {
- accessToken = val.(string)
- return
- }
- //从微信服务器获取
- var resAccessToken ResAccessToken
- resAccessToken, err = GetAccessTokenFromServer(ctx)
- if err != nil {
- return
- }
- accessToken = resAccessToken.Data.AccessToken
- return
- }
- func NewWechatHelper() *WechatHelper {
- appID := os.Getenv("WECHAT_APPID")
- appSecret := os.Getenv("WECHAT_SECRET")
- wx := wechat.NewWechat(&wechat.Config{
- AppID: appID,
- AppSecret: appSecret,
- Cache: wechatCache.NewAccessToken(cache.RedisReport),
- })
- wx.Context.SetGetAccessTokenFunc(MyAccessTokenFunc)
- return &WechatHelper{
- ctx: context.Background(),
- AppId: appID,
- AppSecret: appSecret,
- Wechat: wx,
- }
- }
- type errmsg struct {
- Errcode int `json:"errcode"` //错误码
- Errmsg string `json:"errmsg"` //错误信息
- Result struct {
- Suggest string `json:"suggest"` //建议,有risky、pass、review三种值
- Label int `json:"label"` //命中标签枚举值,100 正常;10001 广告;20001 时政;20002 色情;20003 辱骂;20006 违法犯罪;20008 欺诈;20012 低俗;20013 版权;21000 其他
- } `json:"result"`
- }
- type Subscribe struct {
- ToUser string `json:"touser"`
- TemplateId string `json:"template_id"`
- MiniProgramState string `json:"miniprogram_state"`
- Lang string `json:"lang"`
- Data interface{} `json:"data"`
- }
- func (this *WechatHelper) SendWechatSubscribe(openid string, template string, msg interface{}) int {
- token, _ := this.Wechat.GetAccessToken()
- url := subscribeUrl + token
- logger.Info("send msg use template %s, url %s", template, url)
- reqData := Subscribe{ToUser: openid, TemplateId: template, Lang: "zh_CN"}
- reqData.Data = msg
- data, _ := json.Marshal(reqData)
- buf, err := util.HTTPPost(url, string(data))
- if err != nil {
- logger.Info("[ERROR] CheckWechatMsg post err!err:", err.Error())
- return 101
- }
- var re = new(errmsg)
- err = json.Unmarshal(buf, re)
- if err != nil {
- logger.Info("[ERROR] CheckWechatMsg Unmarshal err!err:", err)
- return 103
- }
- if re.Errcode != 0 {
- if re.Errcode == 40003 || re.Errcode == 43101 { //openid无效,appid与openid不匹配, 用户未订阅消息(用户未在近两小时访问小程序)
- logger.Info("CheckWechatMsg msg: %s ret: %d errmsg: %s", msg, re.Errcode, re.Errmsg)
- return 0
- }
- } else {
- if re.Result.Label != 100 && re.Result.Label != 0 {
- logger.Info("[ERROR]CheckWechatMsg msg:", msg, " ret:", re.Result.Label, " ,suggest:", re.Result.Suggest)
- return re.Result.Label
- }
- }
- logger.Info("==============> %v", re)
- return re.Errcode
- }
|