2024-10-21 17:27:46 +08:00
|
|
|
package weixin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"github.com/tidwall/gjson"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2024-10-22 17:34:18 +08:00
|
|
|
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"
|
2024-10-21 17:27:46 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|