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 }