package weixin import ( "fmt" "github.com/tidwall/gjson" "io" "net/http" "sync" "time" ) const ( code2AccessTokenUrl string = "https://api.weixin.qq.com/sns/oauth2/access_token" jscode2SessionUrl string = "https://api.weixin.qq.com/sns/jscode2session" accessTokenUrl string = "https://api.weixin.qq.com/cgi-bin/token" userPhoneNumberUrl string = "https://api.weixin.qq.com/wxa/business/getuserphonenumber" getWxACodeUnLimitUrl string = "https://api.weixin.qq.com/wxa/getwxacodeunlimit" code2UserinfoUrl string = "https://api.weixin.qq.com/sns/userinfo" oaQrCodeCreateUrl string = "https://api.weixin.qq.com/cgi-bin/qrcode/create" userInfoByOpenid string = "https://api.weixin.qq.com/cgi-bin/user/info" ) type UserInfo struct { Openid string Unionid string AccessToken string Nickname string HeadUrl string Sex int //1:为男性 2位女性 Country string City string Province string } type BaseSdk struct { appid string secret string accessToken string expireIn int64 lock sync.Mutex } func (o *BaseSdk) getAccessToken() (string, error) { o.lock.Lock() defer o.lock.Unlock() if time.Now().Unix() < o.expireIn { return o.accessToken, nil } // 获取一个新token url := fmt.Sprintf("%s?grant_type=client_credential&appid=%s&secret=%s", accessTokenUrl, o.appid, o.secret) res, err := http.Get(url) if err != nil { return "", err } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { return "", err } g := gjson.ParseBytes(body) accessToken := g.Get("access_token").String() if accessToken == "" { return "", fmt.Errorf("%d:%s", g.Get("errcode").Int(), g.Get("errmsg").String()) } o.accessToken = accessToken o.expireIn = time.Now().Unix() + g.Get("expires_in").Int() - 10 return o.accessToken, nil } func (o *BaseSdk) getUserInfoByCode(code string) (*UserInfo, error) { url := fmt.Sprintf("%s?appid=%s&secret=%s&code=%s&grant_type=authorization_code", code2AccessTokenUrl, o.appid, o.secret, code) res, err := http.Get(url) if err != nil { return nil, err } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { return nil, err } g := gjson.ParseBytes(body) errcode := g.Get("errcode").Int() if errcode != 0 { return nil, fmt.Errorf("%d:%s", errcode, g.Get("errmsg").String()) } var user UserInfo user.Unionid = g.Get("unionid").String() user.AccessToken = g.Get("access_token").String() user.Openid = g.Get("openid").String() err = o.getUserInfo(&user) if err != nil { return nil, err } return &user, nil } func (o *BaseSdk) getUserInfo(user *UserInfo) error { url := fmt.Sprintf("%s?access_token=%s&openid=%s&lang=zh_CN", code2UserinfoUrl, user.AccessToken, user.Openid) res, err := http.Get(url) if err != nil { return err } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { return err } g := gjson.ParseBytes(body) errcode := g.Get("errcode").Int() if errcode != 0 { return fmt.Errorf("%d:%s", errcode, g.Get("errmsg").String()) } user.Unionid = g.Get("unionid").String() user.Nickname = g.Get("nickname").String() user.HeadUrl = g.Get("headimgurl").String() user.Province = g.Get("province").String() user.City = g.Get("city").String() user.Country = g.Get("country").String() user.Sex = int(g.Get("sex").Int()) return nil }