first commit

This commit is contained in:
Yangtao
2025-11-18 17:48:20 +08:00
commit 6e56cab848
196 changed files with 65809 additions and 0 deletions

215
pkg/client/wechat_client.go Normal file
View File

@ -0,0 +1,215 @@
package client
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
const (
UserAppID = ""
UserSecret = ""
DriverAppID = ""
DriverSecret = ""
Code2SessionAppURL = "https://api.weixin.qq.com/sns/oauth2/access_token"
UserInfoAppURL = "https://api.weixin.qq.com/sns/userinfo"
Code2SessionJsURL = "https://api.weixin.qq.com/sns/jscode2session"
SendMessageURL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN"
GetAccessTokenURL = "https://api.weixin.qq.com/cgi-bin/token"
)
func WeChatNewAuthJsReqMap(code string) map[string]string {
return map[string]string{
"appid": UserAppID,
"secret": UserSecret,
"js_code": code,
"grant_type": "authorization_code"}
}
func WeChatNewAuthAppReqMap(code string) map[string]string {
return map[string]string{
"appid": UserAppID,
"secret": UserSecret,
"code": code,
"grant_type": "authorization_code"}
}
func WeChatGetAccessTokenReq(_type int) map[string]string {
switch _type {
case 1: // 用户
return map[string]string{
"grant_type": "client_credential",
"appid": UserAppID,
"secret": UserSecret,
}
case 2: // 其他
return map[string]string{
"grant_type": "client_credential",
"appid": DriverAppID,
"secret": DriverSecret,
}
}
return nil
}
// 小程序换取token的返回
type WeChatLoginJsRes struct {
SessionKey string `json:"session_key"`
UnionID string `json:"unionid"`
OpenID string `json:"openid"`
ErrCode int32 `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
// APP换取token的返回
type WeChatLoginAppRes struct {
AccessToken string `json:"access_token"` // 接口调用凭证
ExpiresIn int32 `json:"expires_in"` // access_token 接口调用凭证超时时间,单位(秒)
RefreshToken string `json:"refresh_token"` // 用户刷新 access_token
UnionID string `json:"unionid"` // 用户统一标识。针对一个微信开放平台账号下的应用,同一用户的 unionid 是唯一的
OpenID string `json:"openid"` // 授权用户唯一标识
Scope string `json:"scope"` // 用户授权的作用域,使用逗号(,)分隔
ErrCode int32 `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
// APP获取用户信息
type WeChatUserInfoAppRes struct {
UnionID string `json:"unionid"` // 用户统一标识。针对一个微信开放平台账号下的应用,同一用户的 unionid 是唯一的
OpenID string `json:"openid"` // 授权用户唯一标识
Nickname string `json:"nickname"` // 普通用户昵称
Sex int32 `json:"sex"` // 普通用户性别1 为男性2 为女性
Province string `json:"province"` // 普通用户个人资料填写的省份
City string `json:"city"` // 普通用户个人资料填写的城市
Country string `json:"country"` // 国家,如中国为 CN
Avatar string `json:"headimgurl"` // 用户头像,最后一个数值代表正方形头像大小(有 0、46、64、96、132 数值可选0 代表 640*640 正方形头像),用户没有头像时该项为空
ErrCode int32 `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
// 换取token所用的请求
func WeChatNewAuthReqMapUser(code string) map[string]string {
return map[string]string{
"appid": UserAppID,
"secret": UserSecret,
"js_code": code,
"grant_type": "authorization_code"}
}
// 小程序换取token的请求
func WeChatCode2JsSession(headers map[string]string, params map[string]string) (wxLoginBody WeChatLoginJsRes, e error) {
var (
client = NewClient()
resp *http.Response
res []byte
)
req, _ := http.NewRequest(http.MethodGet, Code2SessionJsURL, nil)
for k, v := range headers {
req.Header.Add(k, v)
}
q := req.URL.Query()
for k, v := range params {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
if resp, e = client.Do(req); e != nil {
return
}
defer func(body io.ReadCloser) {
_ = body.Close()
}(resp.Body)
if res, e = io.ReadAll(resp.Body); e != nil {
return
}
if !success(resp.StatusCode) {
e = fmt.Errorf("status code error: %s", resp.Status)
}
if e = json.Unmarshal(res, &wxLoginBody); e != nil {
return
}
if wxLoginBody.ErrCode != 0 {
e = fmt.Errorf("获取微信登录凭证错误,错误码: %d 错误信息:%s", wxLoginBody.ErrCode, wxLoginBody.ErrMsg)
return
}
return
}
// APP换取token的请求
func WeChatCode2AppToken(headers map[string]string, params map[string]string) (wxLoginBody WeChatLoginAppRes, e error) {
var (
client = NewClient()
resp *http.Response
res []byte
)
req, _ := http.NewRequest(http.MethodGet, Code2SessionAppURL, nil)
for k, v := range headers {
req.Header.Add(k, v)
}
q := req.URL.Query()
for k, v := range params {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
if resp, e = client.Do(req); e != nil {
return
}
defer func(body io.ReadCloser) {
_ = body.Close()
}(resp.Body)
if res, e = io.ReadAll(resp.Body); e != nil {
return
}
if !success(resp.StatusCode) {
e = fmt.Errorf("status code error: %s", resp.Status)
}
if e = json.Unmarshal(res, &wxLoginBody); e != nil {
return
}
if wxLoginBody.ErrCode != 0 {
e = fmt.Errorf("获取微信登录凭证错误,错误码: %d 错误信息:%s", wxLoginBody.ErrCode, wxLoginBody.ErrMsg)
return
}
return
}
// APP获取用户信息
func WeChatUserInfoApp(token, openId string) (wxUserInfoBody WeChatUserInfoAppRes, e error) {
var (
client = NewClient()
resp *http.Response
res []byte
)
req, _ := http.NewRequest(http.MethodGet, UserInfoAppURL, nil)
q := req.URL.Query()
q.Add("access_token", token)
q.Add("openid", openId)
req.URL.RawQuery = q.Encode()
if resp, e = client.Do(req); e != nil {
return
}
defer func(body io.ReadCloser) {
_ = body.Close()
}(resp.Body)
if res, e = io.ReadAll(resp.Body); e != nil {
return
}
if !success(resp.StatusCode) {
e = fmt.Errorf("status code error: %s", resp.Status)
}
if e = json.Unmarshal(res, &wxUserInfoBody); e != nil {
return
}
if wxUserInfoBody.ErrCode != 0 {
e = fmt.Errorf("获取微信登录凭证错误,错误码: %d 错误信息:%s", wxUserInfoBody.ErrCode, wxUserInfoBody.ErrMsg)
return
}
return
}
func success(code int) bool {
return code >= 200 && code < 400
}