-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwechat.go
More file actions
212 lines (201 loc) · 6.86 KB
/
wechat.go
File metadata and controls
212 lines (201 loc) · 6.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
package gwechat
import (
"bytes"
"encoding/json"
qs "github.com/google/go-querystring/query"
ge "github.com/og/go-error"
"io/ioutil"
"net/http"
)
// 接口域名说明
// https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1465199793_BqlKA
const apiDomain = "https://api.weixin.qq.com"
const alternativeAPIDomain = "https://api2.weixin.qq.com"
type Wechat struct {
appID string
appSecret string
centerSerive CenterService
mchID string
mchKey string
}
type wechatErrorJSON struct {
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
type CenterService interface {
GetAccessToken (appID string, appSecret string) (accessToken string , errRes ErrResponse)
GetJSAPITicket(appID string, appSecret string) (ticket string, errRes ErrResponse)
}
type Config struct {
APPID string
APPSecret string
CenterService CenterService
MCHID string
MCHKey string
}
func New (config Config) Wechat {
wechat := Wechat{
appID: config.APPID,
appSecret: config.APPSecret,
centerSerive: config.CenterService,
mchID: config.MCHID,
mchKey: config.MCHKey,
}
return wechat
}
// 获取中控制平台的 access_token
func (this Wechat) GetAccessToken () (accessToken string, err ErrResponse) {
return this.centerSerive.GetAccessToken(this.appID, this.appSecret)
}
// 获取中控制平台的 jsapi_ticket
func (this Wechat) GetJSAPITicket () (ticket string, err ErrResponse) {
return this.centerSerive.GetJSAPITicket(this.appID, this.appSecret)
}
// 长链接转短链接接口
// https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433600
func (this Wechat) GetShortURL (longURL string) (shortURL string, errRes ErrResponse) {
apiPath := "/cgi-bin/shorturl"
type apiQuery struct {
AccessToken string `url:"access_token"`
}
type apiParam struct {
Action string `json:"action"`
LongURL string `json:"long_url"`
}
type apiResponse struct {
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
ShortURL string `json:"short_url"`
}
requestPATH := apiDomain + apiPath
accessToken , errRes := this.GetAccessToken()
if errRes.Fail {
return "", errRes
}
query := apiQuery{
AccessToken: accessToken,
}
param := apiParam {
Action: "long2short", // 此处填long2short,代表长链接转短链接
LongURL: longURL,
}
paramJSON, err := json.Marshal(param); ge.Check(err)
queryValues, err := qs.Values(query); ge.Check(err)
requestURL := requestPATH + "?" + queryValues.Encode()
req, err := http.NewRequest("POST", requestURL, bytes.NewBuffer(paramJSON)); ge.Check(err)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req); ge.Check(err)
if res != nil {
defer res.Body.Close()
}
body, err := ioutil.ReadAll(res.Body); ge.Check(err)
var resData apiResponse
err = json.Unmarshal(body, &resData); ge.Check(err)
if resData.ErrCode != 0 {
errRes.SetFail(resData.ErrCode, resData.ErrMsg)
return "", errRes
}
shortURL = resData.ShortURL
return
}
// 微信网页授权(第一步:用户同意授权,获取code)
// https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#0
// scope 参数使用 wecaht.Dict().WebRedirectAuthorize.Scope 传递
// redirectURI 授权后重定向的回调链接地址, 函数内部已进行 urlEncode 操作,调用方无需 urlEncode
// state 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
// 成功后如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。
func (this Wechat) WebRedirectAuthorize(scope string, redirectURI string, state string) string {
type queryT struct {
AppID string `url:"appid"`
RedirectURI string `url:"redirect_uri"`
ResponseType string `url:"response_type"`
Scope string `url:"scope"`
State string `url:"state"`
}
query := queryT {
AppID: this.appID,
RedirectURI: redirectURI,
ResponseType: "code",
Scope: scope,
State: state,
}
querystring, err := qs.Values(query) ; ge.Check(err)
return "https://open.weixin.qq.com/connect/oauth2/authorize?" + querystring.Encode() + "#wechat_redirect"
}
// 微信网页授权(第二步:通过code换取网页授权access_token)
// https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#1
type WebAccessTokenResponse struct {
wechatErrorJSON
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
OpenID string `json:"openid"`
Scope string `json:"scope"`
}
func (this Wechat) WebAccessToken(code string) (webAccessTokenResponse WebAccessTokenResponse, errRes ErrResponse) {
query := struct {
Code string `url:"code"`
APPID string `url:"appid"`
Secret string `url:"secret"`
GrantType string `url:"grant_type"`
}{
Code: code,
APPID: this.appID,
Secret: this.appSecret,
GrantType: "authorization_code",
}
querystring, err := qs.Values(query); ge.Check(err)
requestURL := apiDomain + "/sns/oauth2/access_token" + "?" + querystring.Encode()
resp, err := http.Get(requestURL); ge.Check(err)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body); ge.Check(err)
err = json.Unmarshal(body, &webAccessTokenResponse); ge.Check(err)
if webAccessTokenResponse.ErrCode != 0 {
errRes.SetFail(webAccessTokenResponse.ErrCode, webAccessTokenResponse.ErrMsg)
return
}
return
}
type WebUserInfoResponse struct {
wechatErrorJSON
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 []string `json:"privilege"`
Unionid string `json:"unionid";comment:"只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。https://open.weixin.qq.com/cgi-bin/index?t=home/index&lang=zh_CN&token=3910897fc2d64d5279f371701325a78824caac9b"`
}
// 微信网页授权(第四步:拉取用户信息(需scope为 snsapi_userinfo))
// https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#3
func (this Wechat) WebGetUserInfo(accessToken string, openID string, lang string) (wechatRes WebUserInfoResponse, errRes ErrResponse) {
type request struct {
AccessToken string `url:"access_token"`
OpenID string `url:"openid"`
Lang string `url:"lang"`
}
query := request{
AccessToken: accessToken,
OpenID: openID,
Lang: lang,
}
querystring, err := qs.Values(query); ge.Check(err)
requestURL := apiDomain + "/sns/userinfo" + "?" + querystring.Encode()
resp, err := http.Get(requestURL); ge.Check(err)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body); ge.Check(err)
err = json.Unmarshal(body, &wechatRes); ge.Check(err)
if wechatRes.ErrCode !=0 {
errRes.SetFail(wechatRes.ErrCode, wechatRes.ErrMsg)
return
}
return
}
type WeappCode2SessionResponse struct {
wechatErrorJSON
OpenID string `json:"openid"`
SessionKey string `json:"session_key"`
}