master v1.0.0
杨赟 2 years ago
commit df52328b0b

1
.gitignore vendored

@ -0,0 +1 @@
.idea

@ -0,0 +1,44 @@
# 微信登录工具
### 公众号
```go
package main
import (
"git.oa00.com/go/wx"
)
func main() {
// 初始化配置
wx.InitWxopen("appid", "secret")
// 获取accessToken和openId
wx.Wxopen.GetAccessInfo("code")
// 获取用户信息
wx.Wxopen.GetUserInfo("accessToken", "openId")
}
```
### 小程序
```go
package main
import (
"git.oa00.com/go/wx"
)
func main() {
// 初始化配置
wx.InitWxapp("appid","secret")
// 获取登录信息
wx.Wxapp.GetLoginInfo("code")
// 获取用户信息
wx.Wxapp.GetUserInfo("sessionKey", "encryptedData", "iv")
// 获取手机号
wx.Wxapp.GetPhone("sessionKey", "encryptedData", "iv")
}
```

@ -0,0 +1,3 @@
module git.oa00.com/go/wx
go 1.17

@ -0,0 +1,80 @@
package wx
import (
"encoding/json"
"errors"
"fmt"
)
var Wxopen = &wxopen{}
type wxopen struct {
appid string
secret string
}
// InitWxopen @Title 初始化开放平台
func InitWxopen(appid, secret string) {
Wxopen.appid = appid
Wxopen.secret = secret
}
type AccessInfo struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
Openid string `json:"openid"`
Scope string `json:"scope"`
Unionid string `json:"unionid"`
}
type errInfo struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
type resAccess struct {
errInfo
AccessInfo
}
// GetAccessInfo @Title 获取微信登录验证结构体
func (w *wxopen) GetAccessInfo(code string) (result AccessInfo, err error) {
res, err := request(get, fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%v&secret=%v&code=%v&grant_type=authorization_code", w.appid, w.secret, code), "")
if err != nil {
return
}
var resAcc resAccess
if err = json.Unmarshal(res, &resAcc); err != nil {
return
}
if resAcc.Errcode != 0 {
return result, errors.New(resAcc.Errmsg)
}
result = resAcc.AccessInfo
return
}
type userInfo struct {
City string `json:"city"`
Country string `json:"country"`
Headimgurl string `json:"headimgurl"`
Nickname string `json:"nickname"`
Openid string `json:"openid"`
Privilege []string `json:"privilege"`
Province string `json:"province"`
Sex uint `json:"sex"`
Unionid string `json:"unionid"`
}
// GetUserInfo @Title 获取微信登录会员信息
func (w *wxopen) GetUserInfo(accessToken, openId string) (*userInfo, error) {
res, err := request(get, fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN", accessToken, openId), "")
if err != nil {
return nil, err
}
result := userInfo{}
if err := json.Unmarshal(res, &result); err != nil {
return nil, err
}
return &result, nil
}

@ -0,0 +1,37 @@
package wx
import (
"io"
"net/http"
"strings"
)
const (
post = "POST"
get = "GET"
)
var client = &http.Client{}
// @Title 请求
func request(method, url, data string, headers ...map[string]string) ([]byte, error) {
reqest, err := http.NewRequest(method, url, strings.NewReader(data))
if err != nil {
return nil, err
}
if len(headers) > 0 {
for key, value := range headers[0] {
reqest.Header.Add(key, value)
}
}
response, err := client.Do(reqest)
if err != nil {
return nil, err
}
defer response.Body.Close()
result, err := io.ReadAll(response.Body)
if err != nil {
return nil, err
}
return result, nil
}

@ -0,0 +1,154 @@
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
}
Loading…
Cancel
Save