forked from royalrick/weapp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathweapp.go
159 lines (127 loc) · 3.59 KB
/
weapp.go
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
package weapp
import (
"encoding/json"
"errors"
"net/http"
"net/url"
"weapp/util"
)
const (
// BaseURL 微信请求基础URL
BaseURL = "https://api.weixin.qq.com"
codeAPI = "/sns/jscode2session"
)
const (
// WeChatServerError 微信服务器错误时返回返回消息
WeChatServerError = "微信服务器发生错误"
)
// Code 微信服务器返回状态码
type Code int
// Response 请求微信返回基础数据
type Response struct {
Errcode Code `json:"errcode,omitempty"`
Errmsg string `json:"errmsg,omitempty"`
}
type loginForm struct {
Response
Openid string `json:"openid"`
SessionKey string `json:"session_key"`
}
// PhoneNumber 解密后的用户手机号码信息
type PhoneNumber struct {
PhoneNumber string `json:"phoneNumber"`
PurePhoneNumber string `json:"purePhoneNumber"`
CountryCode string `json:"countryCode"`
Watermark watermark `json:"watermark"`
}
// Userinfo 解密后的用户信息
type Userinfo struct {
OpenID string `json:"openId"`
Nickname string `json:"nickName"`
Gender int `json:"gender"`
Province string `json:"province"`
Language string `json:"language"`
Country string `json:"country"`
City string `json:"city"`
Avatar string `json:"avatarUrl"`
UnionID string `json:"unionId"`
Watermark watermark `json:"watermark"`
}
// Login 用户登录
// 返回 微信端 openid 和 session_key
func Login(appID, secret, code string) (string, string, error) {
if code == "" {
return "", "", errors.New("code can not be null")
}
api, err := code2url(appID, secret, code)
if err != nil {
return "", "", err
}
res, err := http.Get(api)
if err != nil {
return "", "", err
}
defer res.Body.Close()
if res.StatusCode != 200 {
return "", "", errors.New(WeChatServerError)
}
var data loginForm
err = json.NewDecoder(res.Body).Decode(&data)
if err != nil {
return "", "", err
}
if data.Errcode != 0 {
return "", "", errors.New(data.Errmsg)
}
return data.Openid, data.SessionKey, nil
}
type watermark struct {
AppID string `json:"appid"`
Timestamp int64 `json:"timestamp"`
}
// DecryptPhoneNumber 解密手机号码
//
// @ssk 通过 Login 向微信服务端请求得到的 session_key
// @data 小程序通过 api 得到的加密数据(encryptedData)
// @iv 小程序通过 api 得到的初始向量(iv)
func DecryptPhoneNumber(ssk, data, iv string) (phone PhoneNumber, err error) {
bts, err := util.CBCDecrypt(ssk, data, iv)
if err != nil {
return
}
err = json.Unmarshal(bts, &phone)
return
}
// DecryptUserInfo 解密用户信息
//
// @rawData 不包括敏感信息的原始数据字符串,用于计算签名。
// @encryptedData 包括敏感数据在内的完整用户信息的加密数据
// @signature 使用 sha1( rawData + session_key ) 得到字符串,用于校验用户信息
// @iv 加密算法的初始向量
// @ssk 微信 session_key
func DecryptUserInfo(rawData, encryptedData, signature, iv, ssk string) (ui Userinfo, err error) {
if ok := util.Validate(rawData, ssk, signature); !ok {
err = errors.New("数据校验失败")
return
}
bts, err := util.CBCDecrypt(ssk, encryptedData, iv)
if err != nil {
return
}
err = json.Unmarshal(bts, &ui)
return
}
// 拼接 获取 session_key 的 URL
func code2url(appID, secret, code string) (string, error) {
url, err := url.Parse(BaseURL + codeAPI)
if err != nil {
return "", err
}
query := url.Query()
query.Set("appid", appID)
query.Set("secret", secret)
query.Set("js_code", code)
query.Set("grant_type", "authorization_code")
url.RawQuery = query.Encode()
return url.String(), nil
}