package services import ( "encoding/json" "errors" "fmt" "github.com/rdlucklib/rdluck_tools/http" "hongze/hongze_api/models" "hongze/hongze_api/services/go_redis" "hongze/hongze_api/utils" "strconv" "strings" "time" ) type WxAccessToken struct { AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` RefreshToken string `json:"refresh_token"` Openid string `json:"openid"` Unionid string `json:"unionid"` Scope string `json:"scope"` Errcode int `json:"errcode"` Errmsg string `json:"errmsg"` } func WxGetUserOpenIdByCode(code string) (item *WxAccessToken, err error) { if code == "" { err = errors.New("code is empty") return nil, err } requestUrl := `https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code` requestUrl = fmt.Sprintf(requestUrl, utils.WxAppId, utils.WxAppSecret, code) result, err := http.Get(requestUrl) if err != nil { return nil, err } utils.FileLog.Info("WxGetUserOpenIdByCode:%s", string(result)) err = json.Unmarshal(result, &item) return } type WxToken struct { AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` Errcode int `json:"errcode"` Errmsg string `json:"errmsg"` } func WxGetToken(wxAppId, wxAppSecret string) (item *WxToken, err error) { requestUrl := `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s` requestUrl = fmt.Sprintf(requestUrl, wxAppId, wxAppSecret) fmt.Println("requestUrl:", requestUrl) result, err := http.Get(requestUrl) if err != nil { return nil, err } err = json.Unmarshal(result, &item) fmt.Println("WxGetToken start") fmt.Println(string(result)) fmt.Println("WxGetToken end") return } /*func WxGetAccessToken() (accessToken string, err error) { wxToken, err := models.GetWxToken() fmt.Println(err, wxToken) if err != nil && err.Error() != utils.ErrNoRow() { return } //wx_token 不存在 if wxToken == nil || (err != nil && err.Error() == utils.ErrNoRow()) { token, err := WxGetToken() if err != nil { return accessToken, err } if token.Errmsg != "" { err = errors.New("获取access_token 失败 errcode:" + token.Errmsg + " ;errmsg:" + token.Errmsg) return "", err } expiresIn := time.Now().Add(110 * time.Minute).Unix() err = models.AddWxToken(token.AccessToken, expiresIn) if err != nil { err = errors.New("新增wx_token失败" + err.Error()) return accessToken, err } accessToken = token.AccessToken } else { if wxToken.ExpiresIn <= time.Now().Unix() { token, err := WxGetToken() if err != nil { return accessToken, err } if token.Errmsg != "" { err = errors.New("获取access_token 失败 errcode:" + token.Errmsg + " ;errmsg:" + token.Errmsg) return "", err } expiresIn := time.Now().Add(110 * time.Minute).Unix() err = models.UpdateWxToken(token.AccessToken, expiresIn, wxToken.Id) if err != nil { err = errors.New("修改wx_token失败" + err.Error()) return accessToken, err } accessToken = token.AccessToken } else { accessToken = wxToken.AccessToken } } return }*/ type WxUserInfo struct { Openid string `json:"openid"` Nickname string `json:"nickname"` Sex int `json:"sex"` Language string `json:"language"` City string `json:"city"` Province string `json:"province"` Country string `json:"country"` Headimgurl string `json:"headimgurl"` SubscribeTime int `json:"subscribe_time"` Unionid string `json:"unionid"` Remark string `json:"remark"` Groupid int `json:"groupid"` SubscribeScene string `json:"subscribe_scene"` Errcode int `json:"errcode"` Errmsg string `json:"errmsg"` } func WxGetUserInfo(openId, accessToken string) (item *WxUserInfo, err error) { requestUrl := `https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s` requestUrl = fmt.Sprintf(requestUrl, accessToken, openId) result, err := http.Get(requestUrl) if err != nil { return } fmt.Println("result:", string(result)) utils.FileLog.Info("WxGetUserInfo:%s openId:%s,accessToken:%s ", string(result), openId, accessToken) utils.FileLog.Info("WxGetUserInfo Result:%s ", string(result)) err = json.Unmarshal(result, &item) return } func GetWxTicket(accessToken string) (string, error) { Url := strings.Join([]string{"https://api.weixin.qq.com/cgi-bin/ticket/getticket", "?access_token=", accessToken, "&type=jsapi"}, "") infoBody, err := http.Get(Url) if err != nil { return "", err } atr := models.WxTicket{} err = json.Unmarshal(infoBody, &atr) fmt.Println("ticket result:", string(infoBody)) if err != nil { return atr.Errmsg, err } else { return atr.Ticket, nil } } func GetWxSignature(ticket, url, noncestr string) (string, string, int64) { timestamp := time.Now().Unix() signStr := strings.Join([]string{"jsapi_ticket=", ticket, "&noncestr=", noncestr, "×tamp=", strconv.FormatInt(timestamp, 10), "&url=", url}, "") signature := utils.Sha1(signStr) fmt.Println("signStr", signStr) return signature, noncestr, timestamp } type WxUserDetail struct { Unionid string Headimgurl string Nickname string } func FixUnionId() { accessToken := `41_fMVI8r0fzoDjGOsKjMBhVN9b0j34TWTFNHIX1cQ4IOJ8SnJ2Cjz6MhvHvtH9gU_ztKo-rRQopCgSjNSZB5z25KgB5o61822LDH1sR5ow_Rfoa_Ro6KwcdP2Gp_naNM0AwMGZaF5OMifMny-FFEXfAJAXWP` users, err := models.GetOpenIdAll() if err != nil { fmt.Println("GetOpenIdAll Err:" + err.Error()) return } for _, v := range users { openId := v.OpenId fmt.Println("openId:", openId, v.UserId) userInfoUrl := `https://api.weixin.qq.com/cgi-bin/user/info?access_token=` + accessToken + `&openid=` + openId + `&lang=zh_CN` result, err := http.Get(userInfoUrl) fmt.Println("err:", err) utils.FileLog.Info("%s", string(result)) item := new(WxUserDetail) err = json.Unmarshal(result, &item) if err != nil { fmt.Println("json.Unmarshal Err:" + err.Error()) return } if item.Unionid != "" { err = models.ModifyWxUserUnionId(item.Unionid, v.UserId) if err != nil { fmt.Println("ModifyWxUserUnionId Err:" + err.Error()) return } //return } } } // GetDefaultWxAccessToken 获取微信token func GetDefaultWxAccessToken() (accessToken string, err error, errMsg string) { // 微信配置信息 conf, e := models.GetBusinessConf() if e != nil { errMsg = "获取配置信息失败, Err: " + e.Error() err = errors.New(errMsg) return } appId := "" appSecret := "" if v, ok := conf[models.BusinessConfWxAppId]; ok { appId = v } if v, ok := conf[models.BusinessConfWxAppSecret]; ok { appSecret = v } if appId == "" || appSecret == "" { errMsg = "获取微信公众号未配置" err = errors.New(errMsg) return } accessToken, err, errMsg = GetWxAccessToken(appId, appSecret) return } // GetWxAccessToken 获取微信token func GetWxAccessToken(wxAppId, wxAppSecret string) (accessToken string, err error, errMsg string) { redisKey := getRedisKeyByAppid(wxAppId) if redisKey == `` { errMsg = "未配置缓存key" err = errors.New(errMsg) return } accessToken, err = go_redis.RedisString(redisKey) //fmt.Println(err) //fmt.Println(accessToken) //if err != nil { // errMsg = "GetWxAccessToken Err:" + err.Error() // utils.FileLog.Info("获取Token失败,msg:" + errMsg) // return //} //取到数据后就直接返回了,没有后续了 if accessToken != "" { return } //缓存中没有取到数据,那么需要去强制刷新新的accessToken return refreshWxAccessToken(wxAppId, wxAppSecret) } // refreshWxAccessToken 强制刷新微信token func refreshWxAccessToken(wxAppId, wxAppSecret string) (accessToken string, err error, errMsg string) { fmt.Println("强制刷新" + wxAppId + "微信token") defer func() { if errMsg != `` { utils.FileLog.Info(fmt.Sprintf("强制刷新%s微信token异常:%s", wxAppId, errMsg)) } }() redisKey := getRedisKeyByAppid(wxAppId) if redisKey == `` { errMsg = "未配置缓存key" err = errors.New(errMsg) return } if wxAppSecret == "" { err = errors.New("缺少密钥信息") utils.FileLog.Info(fmt.Sprintf("获取Token失败, errMsg:%s", err.Error())) return } //调用微信官方接口获取新的accessToken wxAccessToken, tmpErr := WxGetToken(wxAppId, wxAppSecret) if tmpErr != nil { err = tmpErr errMsg = "通过微信接口获取accessToken失败 Err:" + err.Error() return } //如果没有token数据 if wxAccessToken.AccessToken == "" { errMsg = "微信返回的accessToken异常: Err:" + wxAccessToken.Errmsg err = errors.New(errMsg) return } accessToken = wxAccessToken.AccessToken //如果是弘则研究的appid,那么需要更新mysql的accessToken if wxAppId == utils.WxAppId { expiresIn := time.Now().Add(time.Duration(wxAccessToken.ExpiresIn) * time.Second).Unix() err = models.ModifyAccessToken(wxAccessToken.AccessToken, expiresIn) if err != nil { errMsg = "更新mysql中的accessToken失败 Err:" + err.Error() return } } //更新redis的accessToken(过期时间提前十分钟) redisTimeExpire := time.Duration(wxAccessToken.ExpiresIn-600) * time.Second bo := go_redis.SetNX(redisKey, accessToken, redisTimeExpire) if !bo { errMsg = "更新redis中的accessToken失败" return } return } // 根据微信appid获取对应的缓存key func getRedisKeyByAppid(wxAppId string) (redisKey string) { switch wxAppId { case utils.WxAppId: redisKey = utils.CACHE_WX_ACCESS_TOKEN_HZ } return redisKey }