/
alipay_client.go
260 lines (225 loc) · 8.01 KB
/
alipay_client.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
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
package alipay
import (
"crypto"
"crypto/rsa"
"fmt"
"net/http"
"time"
)
type AliClient struct {
appId string //应用id
format string //JSON
signType string //商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2
charset string //编码格式utf-8
aliGateway string //支付宝网关地址,沙箱:https://openapi-sandbox.dl.alipaydev.com/gateway.do 正式:https://openapi.alipay.com/gateway.do
privateKey *rsa.PrivateKey //商户私钥
publicKey *rsa.PublicKey //支付宝公钥
environment string //"sandbox"沙箱;"production"生产环境
httpClient *http.Client //http客户端
}
func NewAliClient(appId, format, charset, signType, environment string, aliPrivateKey *rsa.PrivateKey, aliPublicKey *rsa.PublicKey) *AliClient {
client := AliClient{
appId: appId,
format: format,
signType: signType,
environment: environment,
charset: charset,
privateKey: aliPrivateKey,
publicKey: aliPublicKey,
httpClient: http.DefaultClient, //先使用默认客户端
}
if environment == CLIENT_ENVIRONMENT_PROD {
client.aliGateway = GATEWAY_URL_PROD
} else if environment == CLIENT_ENVIRONMENT_SB {
client.aliGateway = GATEWAY_URL_SB
}
return &client
}
// SyncVerifySign 同步响应签名校验: scene验签场景 sign待验证的签名 buff待验证的内容 sertSn支付宝公钥证书序列号(公钥证书模式下,同步响应时使用)
func (client *AliClient) SyncVerifySign(sign, buff string) error {
//同步响应验签
err := RSAVerifyWithKey([]byte(buff), []byte(sign), client.publicKey, crypto.SHA256)
if err != nil {
return err
}
return nil
}
// 发起请求
func (client *AliClient) DoRequest(appId, appAuthToken, notifyUrl string, apiReq IRequester) (IResponse, error) {
commonReq := CommonRequestParam{
AppId: appId,
Method: apiReq.ApiParamMethod(),
Format: client.format,
Charset: client.charset,
SignType: client.signType,
Sign: "",
Timestamp: time.Now().Format("2006-01-02 15:04:05"),
Version: "1.0",
NotifyUrl: notifyUrl,
BizContent: "", //除公共参数外的所有参数
AppAuthToken: appAuthToken, //灵活数据,要作为参数传入
}
_, err := commonReq.SetRequestBizContent(apiReq)
if err != nil {
return nil, err
}
// 设置请求签名
_, err = commonReq.SetRequestSign(client.privateKey)
if err != nil {
return nil, err
}
// 构建请求参数
paramStr, err := commonReq.GenRequestParamStr()
if err != nil {
return nil, err
}
// 发起请求
resp, err := client.doRequest(apiReq, []byte(paramStr))
if err != nil {
return resp, err
}
return resp, nil
}
// 处理http层数据
func (client *AliClient) doRequest(apiReq IRequester, param []byte) (IResponse, error) {
// 参数校验
err := apiReq.DoValidate()
if err != nil {
return nil, err
}
// 发起请求
method := apiReq.HttpMethod()
resp, err := HttpDoRequest(client.httpClient, method, client.aliGateway, param)
if err != nil {
return nil, err
}
fmt.Println(string(resp))
respBuff := RBuffer(resp)
// 准备验签数据
awaitSignData, err := respBuff.GetSyncRespSignData()
if err != nil {
return nil, err
}
sign, err := respBuff.GetSyncRespSign()
if err != nil {
return nil, err
}
// 验签
err = client.SyncVerifySign(sign, awaitSignData)
if err != nil {
return nil, err
}
// 处理业务层错误
//if respBuff.IsBadResponse() {
// type tempResponse struct {
// AlipayTradePayResponse ErrorParam `json:"alipay_trade_pay_response"`
// }
// var errResp tempResponse
// err = json.Unmarshal(resp, &errResp)
// if err != nil {
// return nil, err
// }
// err = errors.New(errResp.AlipayTradePayResponse.GetBadResponseDesc())
// return nil, err
//}
apiResp, err := apiReq.GenResponse(resp)
if err != nil {
return nil, err
}
fmt.Println(apiResp)
err = apiResp.IsBadResponse()
if err != nil {
return nil, err
}
return apiResp, nil
}
// AsyncRequestCheckSign 异步通知请求验签
func (client *AliClient) AsyncRequestGetParamAndCheckSign(reqBuff []byte) (map[string]string, error) {
reqParam, signData, sign, err := RBuffer(reqBuff).GetAsyncRequestSignStr()
if err != nil {
return reqParam, err
}
err = RSAVerifyWithKey([]byte(signData), []byte(sign), client.publicKey, crypto.SHA256)
if err != nil {
return reqParam, err
}
return reqParam, nil
}
// AliPayOpenAuthTokenApp 换取应用授权令牌
func (client *AliClient) AliPayOpenAuthTokenApp(openAuthTokenAppRequest OpenAuthTokenAppRequest) (OpenAuthTokenAppResponse, error) {
resp, err := client.DoRequest(client.appId, "", "", &openAuthTokenAppRequest)
if err != nil {
return OpenAuthTokenAppResponse{}, err
}
tradePayResponse, ok := resp.(OpenAuthTokenAppResponse)
if !ok {
err = fmt.Errorf("响应结构不匹配方法%s", openAuthTokenAppRequest.ApiParamMethod())
return OpenAuthTokenAppResponse{}, err
}
return tradePayResponse, nil
}
// AliPayTradPay 统一收单交易支付接口(alipay.trade.pay): 收银员使用扫码枪读取用户手机支付宝支付码
func (client *AliClient) AliPayTradPay(appAuthToken string, notifyUrl string, tradePayRequest TradePayRequest) (TradePayResponse, error) {
resp, err := client.DoRequest(client.appId, appAuthToken, notifyUrl, &tradePayRequest)
if err != nil {
return TradePayResponse{}, err
}
tradePayResponse, ok := resp.(TradePayResponse)
if !ok {
err = fmt.Errorf("响应结构不匹配方法%s", tradePayRequest.ApiParamMethod())
return TradePayResponse{}, err
}
return tradePayResponse, nil
}
// AliPayTradeQuery 统一收单交易查询(alipay.trade.query)
func (client *AliClient) AliPayTradeQuery(appAuthToken string, tradeQueryRequest TradeQueryRequest) (TradeQueryResponse, error) {
resp, err := client.DoRequest(client.appId, appAuthToken, "", &tradeQueryRequest)
if err != nil {
return TradeQueryResponse{}, err
}
tradeQueryResponse, ok := resp.(TradeQueryResponse)
if !ok {
err = fmt.Errorf("响应结构不匹配方法%s", tradeQueryRequest.ApiParamMethod())
return TradeQueryResponse{}, err
}
return tradeQueryResponse, nil
}
// AliPayTradeRefund 统一收单交易退款接口(alipay.trade.refund) 只有在支付时填写回调地址,才会收到退款通知
func (client *AliClient) AliPayTradeRefund(appAuthToken string, notifyUrl string, tradeRefundRequest TradeRefundRequest) (TradeRefundResponse, error) {
resp, err := client.DoRequest(client.appId, appAuthToken, notifyUrl, &tradeRefundRequest)
if err != nil {
return TradeRefundResponse{}, err
}
tradeRefundResponse, ok := resp.(TradeRefundResponse)
if !ok {
err = fmt.Errorf("响应结构不匹配方法%s", tradeRefundRequest.ApiParamMethod())
return TradeRefundResponse{}, err
}
return tradeRefundResponse, nil
}
// AliPayTradeFastPayRefundQuery 统一收单交易退款查询(alipay.trade.fastpay.refund.query)
func (client *AliClient) AliPayTradeFastPayRefundQuery(appAuthToken string, tradeFastPayRefundQueryRequest TradeFastPayRefundQueryRequest) (TradeFastPayRefundQueryResponse, error) {
resp, err := client.DoRequest(client.appId, appAuthToken, "", &tradeFastPayRefundQueryRequest)
if err != nil {
return TradeFastPayRefundQueryResponse{}, err
}
tradeFastPayRefundQueryResponse, ok := resp.(TradeFastPayRefundQueryResponse)
if !ok {
err = fmt.Errorf("响应结构不匹配方法%s", tradeFastPayRefundQueryRequest.ApiParamMethod())
return TradeFastPayRefundQueryResponse{}, err
}
return tradeFastPayRefundQueryResponse, nil
}
// AliPayTradeCancel 统一收单交易撤销接口(alipay.trade.cancel)
func (client *AliClient) AliPayTradeCancel(appAuthToken string, tradeCancelRequest TradeCancelRequest) (TradeCancelResponse, error) {
resp, err := client.DoRequest(client.appId, appAuthToken, "", &tradeCancelRequest)
if err != nil {
return TradeCancelResponse{}, err
}
tradeCancelResponse, ok := resp.(TradeCancelResponse)
if !ok {
err = fmt.Errorf("响应结构不匹配方法%s", tradeCancelRequest.ApiParamMethod())
return TradeCancelResponse{}, err
}
return tradeCancelResponse, nil
}