You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
3.6 KiB

package wx
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"log"
)
var Wxapp = &wxapp{}
type wxapp struct {
appid string
secret string
}
// InitWxapp @Title 初始化wxapp
func InitWxapp(appid, secret string) {
Wxapp.appid = appid
Wxapp.secret = secret
}
type resLogin struct {
LoginInfo
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
type LoginInfo struct {
SessionKey string `json:"session_key"`
Openid string `json:"openid"`
Unionid string `json:"unionid"`
}
// GetLoginInfo @Title 获取登录信息
func (w *wxapp) GetLoginInfo(code string) (info LoginInfo, err error) {
bytes, err := request("get", fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
w.appid, w.secret, code), "")
if err != nil {
return
}
log.Println(string(bytes))
res := resLogin{}
if err = json.Unmarshal(bytes, &res); err != nil {
return
}
if res.Errcode > 0 {
return info, errors.New(res.Errmsg)
}
return res.LoginInfo, nil
}
type UserInfo struct {
OpenID string `json:"openId"`
UnionID string `json:"unionId"`
NickName string `json:"nickName"`
Gender int `json:"gender"`
City string `json:"city"`
Province string `json:"province"`
Country string `json:"country"`
AvatarURL string `json:"avatarUrl"`
Language string `json:"language"`
Watermark struct {
Timestamp int64 `json:"timestamp"`
AppID string `json:"appid"`
} `json:"watermark"`
}
// GetUserInfo @Title 获取用户信息
func (w *wxapp) GetUserInfo(sessionKey, encryptedData, iv string) (userInfo UserInfo, err error) {
decrypt, err := w.Decrypt(sessionKey, encryptedData, iv)
if err != nil {
return
}
err = json.Unmarshal(decrypt, &userInfo)
if err != nil {
return
}
if userInfo.Watermark.AppID != w.appid {
return userInfo, errors.New("app id not match")
}
return
}
type UserPhone struct {
PhoneNumber string `json:"phoneNumber"`
PurePhoneNumber string `json:"purePhoneNumber"`
CountryCode string `json:"countryCode"`
Watermark struct {
Timestamp int `json:"timestamp"`
Appid string `json:"appid"`
} `json:"watermark"`
}
// GetPhone @Title 获取用户手机号
func (w *wxapp) GetPhone(sessionKey, encryptedData, iv string) (userPhone UserPhone, err error) {
decrypt, err := w.Decrypt(sessionKey, encryptedData, iv)
if err != nil {
return
}
if err = json.Unmarshal(decrypt, &userPhone); err != nil {
return
}
return
}
// Decrypt @Title 解密数据
func (w *wxapp) Decrypt(sessionKey, encryptedData, iv string) (decrypt []byte, err error) {
aesKey, err := base64.StdEncoding.DecodeString(sessionKey)
if err != nil {
return
}
cipherText, err := base64.StdEncoding.DecodeString(encryptedData)
if err != nil {
return
}
ivBytes, err := base64.StdEncoding.DecodeString(iv)
if err != nil {
return
}
block, err := aes.NewCipher(aesKey)
if err != nil {
return
}
mode := cipher.NewCBCDecrypter(block, ivBytes)
mode.CryptBlocks(cipherText, cipherText)
decrypt, err = w.pkcs7Unpad(cipherText, block.BlockSize())
if err != nil {
return
}
return
}
func (w *wxapp) pkcs7Unpad(data []byte, blockSize int) ([]byte, error) {
if blockSize <= 0 {
return nil, errors.New("invalid block size")
}
if len(data)%blockSize != 0 || len(data) == 0 {
return nil, errors.New("invalid PKCS7 data")
}
c := data[len(data)-1]
n := int(c)
if n == 0 || n > len(data) {
return nil, errors.New("invalid padding on input")
}
for i := 0; i < n; i++ {
if data[len(data)-n+i] != c {
return nil, errors.New("invalid padding on input")
}
}
return data[:len(data)-n], nil
}