weixin
This commit is contained in:
parent
acc8f15a06
commit
784b361ec8
|
@ -0,0 +1,18 @@
|
||||||
|
package weixin
|
||||||
|
|
||||||
|
type AppSdk struct {
|
||||||
|
BaseSdk
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAppSdk(appid, secret string) *AppSdk {
|
||||||
|
return &AppSdk{
|
||||||
|
BaseSdk{
|
||||||
|
appid: appid,
|
||||||
|
secret: secret,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *AppSdk) GetUserInfoByCode(code string) (*UserInfo, error) {
|
||||||
|
return o.getUserInfoByCode(code)
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
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"
|
||||||
|
accessToken2UserInfoUrl string = "https://api.weixin.qq.com/sns/userinfo"
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
package weixin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cast"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MpSdk struct {
|
||||||
|
BaseSdk
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMpSdk(appid, secret string) *MpSdk {
|
||||||
|
return &MpSdk{
|
||||||
|
BaseSdk{
|
||||||
|
appid: appid,
|
||||||
|
secret: secret,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *MpSdk) GetUserInfoByJsCode(code string) (*UserInfo, error) {
|
||||||
|
url := fmt.Sprintf("%s?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
|
||||||
|
jscode2SessionUrl, 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
|
||||||
|
}
|
||||||
|
userInfo := new(UserInfo)
|
||||||
|
|
||||||
|
g := gjson.ParseBytes(body)
|
||||||
|
userInfo.Openid = g.Get("openid").String()
|
||||||
|
userInfo.Unionid = g.Get("unionid").String()
|
||||||
|
return userInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *MpSdk) GetPhone(code string) (string, error) {
|
||||||
|
accessToken, err := o.getAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
reqUrl := fmt.Sprintf("%s?access_token=%s", userPhoneNumberUrl, accessToken)
|
||||||
|
res, err := http.Post(reqUrl, "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(`{"code":"%s"}`, code))))
|
||||||
|
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"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return g.Get("phone_info.phoneNumber").String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *MpSdk) GetUnlimitedQRCode(params map[string]interface{}) ([]byte, error) {
|
||||||
|
if _, ok := params["scene"]; !ok {
|
||||||
|
return nil, errors.New("scene参数缺失")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := params["width"]; !ok {
|
||||||
|
params["width"] = 280
|
||||||
|
}
|
||||||
|
if _, ok := params["env_version"]; !ok {
|
||||||
|
params["env_version"] = "release"
|
||||||
|
}
|
||||||
|
if _, ok := params["check_path"]; !ok {
|
||||||
|
params["check_path"] = false
|
||||||
|
}
|
||||||
|
if _, ok := params["page"]; !ok {
|
||||||
|
params["page"] = "pages/index/index"
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal, _ := json.Marshal(params)
|
||||||
|
accessToken, err := o.getAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf("%s?access_token=%s", getWxACodeUnLimitUrl, accessToken)
|
||||||
|
res, _ := http.Post(url, "application/json", bytes.NewBuffer(marshal))
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mp := make(map[string]interface{})
|
||||||
|
err = json.Unmarshal(body, &mp)
|
||||||
|
if err == nil {
|
||||||
|
return nil, fmt.Errorf("%d:%s", cast.ToInt64(mp["errcode"]), cast.ToString(mp["errmsg"]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return body, nil
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
package weixin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OaSdk struct {
|
||||||
|
BaseSdk
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOaSdk(appid, secret string) *OaSdk {
|
||||||
|
return &OaSdk{
|
||||||
|
BaseSdk{
|
||||||
|
appid: appid,
|
||||||
|
secret: secret,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OaSdk) GetQrCode(sceneStr string) (string, error) {
|
||||||
|
params := make(map[string]interface{})
|
||||||
|
params["expire_seconds"] = 1728000 //20天
|
||||||
|
params["action_name"] = "QR_STR_SCENE"
|
||||||
|
params["action_info"] = map[string]interface{}{
|
||||||
|
"scene": map[string]interface{}{
|
||||||
|
"scene_str": sceneStr, // sceneStr不超过64个字符
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal, _ := json.Marshal(params)
|
||||||
|
accessToken, err := o.getAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("?access_token=%s", oaQrCodeCreateUrl, accessToken)
|
||||||
|
res, _ := http.Post(url, "application/json", bytes.NewBuffer(marshal))
|
||||||
|
defer res.Body.Close()
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
g := gjson.ParseBytes(body)
|
||||||
|
|
||||||
|
qrcodeUrl := g.Get("url").String()
|
||||||
|
if qrcodeUrl == "" {
|
||||||
|
return "", fmt.Errorf("%d:%s", g.Get("errcode").Int(), g.Get("errmsg").String())
|
||||||
|
}
|
||||||
|
return qrcodeUrl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *BaseSdk) GetUserInfoByCode(code string) (*UserInfo, error) {
|
||||||
|
return o.getUserInfoByCode(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OaSdk) GetUserInfoByOpenid(openid string) (*UserInfo, error) {
|
||||||
|
accessToken, err := o.getAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf("%s?access_token=%s&openid=%s&lang=zh_CN",
|
||||||
|
userInfoByOpenid, accessToken, openid)
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
user := new(UserInfo)
|
||||||
|
user.Unionid = g.Get("unionid").String()
|
||||||
|
user.Nickname = g.Get("nickname").String()
|
||||||
|
user.Province = g.Get("province").String()
|
||||||
|
user.City = g.Get("city").String()
|
||||||
|
user.Country = g.Get("country").String()
|
||||||
|
user.HeadUrl = g.Get("headimgurl").String()
|
||||||
|
user.Sex = int(g.Get("sex").Int())
|
||||||
|
user.Openid = openid
|
||||||
|
return user, nil
|
||||||
|
}
|
Loading…
Reference in New Issue