Files
baseapi/platformapi/weixinapi/sns.go
2025-11-21 09:09:09 +08:00

236 lines
7.0 KiB
Go

package weixinapi
import (
"bytes"
"encoding/json"
"errors"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/globals"
)
type SNSTokenInfo struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
OpenID string `json:"openid"`
Scope string `json:"scope"`
}
type SNSUserInfo struct {
OpenID string `json:"openid"`
NickName string `json:"nickname"`
Sex int `json:"sex"`
Province string `json:"province"`
City string `json:"city"`
Country string `json:"country"`
HeadImgURL string `json:"headimgurl"`
Privilege interface{} `json:"privilege"`
UnionID string `json:"unionid"`
}
type SessionInfo struct {
OpenID string `json:"openid"`
SessionKey string `json:"session_key"`
UnionID string `json:"unionid"`
}
type MiniUserInfo struct {
OpenID string `json:"openId"`
NickName string `json:"nickName"`
Gender int `json:"gender"`
Language string `json:"language"`
City string `json:"city"`
PhoneNumber string `json:"phoneNumber"`
PurePhoneNumber string `json:"purePhoneNumber"`
Province string `json:"province"`
Country string `json:"country"`
CountryCode string `json:"countryCode"`
AvatarURL string `json:"avatarUrl"`
UnionID string `json:"unionId"`
Watermark struct {
Timestamp int `json:"timestamp"`
Appid string `json:"appid"`
} `json:"watermark"`
}
type GetUserPhone struct {
ErrCode int64 `json:"errcode"`
ErrMsg string `json:"errmsg"`
PhoneInfo *UserPhone `json:"phone_info"`
}
// UserPhone 微信小程序解密后 用户手机号结构体
type UserPhone struct {
PhoneNumber string `json:"phoneNumber,omitempty"`
PurePhoneNumber string `json:"purePhoneNumber,omitempty"`
CountryCode string `json:"countryCode,omitempty"`
Watermark *watermarkInfo `json:"watermark,omitempty"`
}
type watermarkInfo struct {
Appid string `json:"appid,omitempty"`
Timestamp int `json:"timestamp,omitempty"`
}
func mapData2SNSToken(result map[string]interface{}) *SNSTokenInfo {
return &SNSTokenInfo{
AccessToken: utils.Interface2String(result["access_token"]),
ExpiresIn: int(utils.MustInterface2Int64(result["expires_in"])),
RefreshToken: utils.Interface2String(result["refresh_token"]),
OpenID: utils.Interface2String(result["openid"]),
Scope: utils.Interface2String(result["scope"]),
}
}
func (a *API) SNSRetrieveToken(code string) (tokenInfo *SNSTokenInfo, err error) {
result, err := a.AccessAPI("sns/oauth2/access_token", utils.Params2Map("grant_type", "authorization_code", "code", code), "")
if err != nil {
globals.SugarLogger.Debugf("SNSRetrieveToken err=%v", err)
return nil, err
}
globals.SugarLogger.Debugf("SNSRetrieveToken result=%s", mapData2SNSToken(result))
return mapData2SNSToken(result), nil
}
func (a *API) SNSRefreshToken(refreshToken string) (tokenInfo *SNSTokenInfo, err error) {
result, err := a.AccessAPI("sns/oauth2/refresh_token", utils.Params2Map("grant_type", "refresh_token", "refresh_token", refreshToken), "")
if err != nil {
return nil, err
}
return mapData2SNSToken(result), nil
}
func (a *API) SNSGetUserInfo(accessToken, openid string) (*SNSUserInfo, error) {
result, err := a.AccessAPI("sns/userinfo", map[string]interface{}{
"access_token": accessToken,
"openid": openid,
}, "")
if err == nil {
retVal := &SNSUserInfo{
OpenID: utils.Interface2String(result["openid"]),
NickName: utils.Interface2String(result["nickname"]),
Sex: int(utils.MustInterface2Int64(result["sex"])),
Province: utils.Interface2String(result["province"]),
City: utils.Interface2String(result["city"]),
Country: utils.Interface2String(result["country"]),
HeadImgURL: utils.Interface2String(result["headimgurl"]),
Privilege: result["privilege"],
UnionID: utils.Interface2String(result["unionid"]),
}
return retVal, nil
}
return nil, err
}
func (a *API) SNSIsOpenIDValid(accessToken, openid string) (bool, error) {
_, err := a.AccessAPI("sns/auth", map[string]interface{}{
"access_token": accessToken,
"openid": openid,
}, "")
if err == nil {
return true, nil
}
return false, err
}
func (a *API) SNSCode2Session(jsCode string) (sessionInfo *SessionInfo, err error) {
result, err := a.AccessAPI("sns/jscode2session", map[string]interface{}{
"js_code": jsCode,
"grant_type": "authorization_code",
}, "")
if err == nil {
return &SessionInfo{
OpenID: utils.Interface2String(result["openid"]),
SessionKey: utils.Interface2String(result["session_key"]),
UnionID: utils.Interface2String(result["unionid"]),
}, nil
}
return nil, err
}
func (a *API) SNSGetUserPhone(jsCode string) (string, error) {
url := "wxa/business/getuserphonenumber"
if a.token == "" {
a.CBRetrieveToken()
}
bodyJson := map[string]interface{}{
"code": jsCode,
}
result, err := a.AccessAPI(url, nil, string(utils.MustMarshal(bodyJson)))
if err != nil {
return "", err
}
var phoneInfo *GetUserPhone
if err := utils.Map2StructByJson(result, &phoneInfo, false); err != nil {
return "", err
}
if phoneInfo.ErrCode != 0 {
return "", errors.New(phoneInfo.ErrMsg)
}
return phoneInfo.PhoneInfo.PhoneNumber, nil
}
// 获取小程序短连接CBRetrieveToken
func (a *API) MiniProgramSortLink() (string, error) {
weChatToken := ""
token := a.CBGetToken()
if token == "" {
newToken, err := a.CBRetrieveToken()
if err != nil {
return "", err
}
weChatToken = newToken.AccessToken
} else {
weChatToken = token
}
parmaJson := map[string]interface{}{
"access_token": weChatToken,
}
bodyJson := map[string]interface{}{
//"access_token ": weChatToken,
"expire_type": 1,
"expire_interval": 1,
}
body, _ := json.Marshal(bodyJson)
result, err := a.AccessAPI("wxa/generate_urllink", parmaJson, string(body))
if err != nil {
return "", err
}
errCode, _ := result["errcode"].(json.Number).Int64()
if errCode != 0 {
return "", errors.New(result["errmsg"].(string))
}
return result["url_link"].(string), nil
}
// 待删除
func (a *API) SNSDecodeMiniProgramData(encryptedData, sessionKey, iv string) (decryptedData []byte, err error) {
return SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
}
func SNSDecodeMiniProgramData(encryptedData, sessionKey, iv string) (decryptedData []byte, err error) {
decodedDataList, err := utils.Base64DecodeMultiString(encryptedData, sessionKey, iv)
if err != nil {
return nil, err
}
decryptedData, err = utils.AESCBCDecpryt(decodedDataList[0], decodedDataList[1], decodedDataList[2])
return decryptedData, err
}
func PKCSUnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
func PKCSPadding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}