+alipayapi
This commit is contained in:
162
platformapi/alipayapi/alipayapi.go
Normal file
162
platformapi/alipayapi/alipayapi.go
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
package alipayapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi"
|
||||||
|
"git.rosy.net.cn/baseapi/platformapi"
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
prodURL = "https://openapi.alipay.com/gateway.do"
|
||||||
|
|
||||||
|
signKey = "sign"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CommonErrSuccess = "10000"
|
||||||
|
CommonErrServiceNotAvailable = "20000"
|
||||||
|
)
|
||||||
|
|
||||||
|
type API struct {
|
||||||
|
appID string
|
||||||
|
privateKey *rsa.PrivateKey
|
||||||
|
client *http.Client
|
||||||
|
config *platformapi.APIConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
commonCanRetryErrMap = map[string]bool{
|
||||||
|
CommonErrServiceNotAvailable: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(appID string, privateKey interface{}, config ...*platformapi.APIConfig) (a *API) {
|
||||||
|
curConfig := platformapi.DefAPIConfig
|
||||||
|
if len(config) > 0 {
|
||||||
|
curConfig = *config[0]
|
||||||
|
}
|
||||||
|
var keyBytes []byte
|
||||||
|
if keyBytes2, ok := privateKey.([]byte); ok {
|
||||||
|
keyBytes = keyBytes2
|
||||||
|
} else {
|
||||||
|
keyBytes, _ = ioutil.ReadFile(privateKey.(string))
|
||||||
|
}
|
||||||
|
pubPem, _ := pem.Decode(keyBytes)
|
||||||
|
if pubPem == nil {
|
||||||
|
keyBytes, _ = base64.StdEncoding.DecodeString(string(keyBytes))
|
||||||
|
} else {
|
||||||
|
keyBytes = pubPem.Bytes
|
||||||
|
}
|
||||||
|
a = &API{
|
||||||
|
appID: appID,
|
||||||
|
client: &http.Client{Timeout: curConfig.ClientTimeout},
|
||||||
|
config: &curConfig,
|
||||||
|
}
|
||||||
|
if privateKey, err := x509.ParsePKCS1PrivateKey(keyBytes); err == nil {
|
||||||
|
a.privateKey = privateKey
|
||||||
|
} else {
|
||||||
|
baseapi.SugarLogger.Errorf("alpayapi.New failed with err:%v", err)
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) GetAppID() string {
|
||||||
|
return a.appID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) signParams(params map[string]interface{}) (sign string) {
|
||||||
|
keys := make([]string, 0)
|
||||||
|
for k := range params {
|
||||||
|
if k != signKey {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
strList := make([]string, len(keys))
|
||||||
|
for index, k := range keys {
|
||||||
|
strList[index] = fmt.Sprintf("%s=%v", k, params[k])
|
||||||
|
}
|
||||||
|
|
||||||
|
finalStr := strings.Join(strList, "&")
|
||||||
|
// baseapi.SugarLogger.Debugf("finalStr:%s", finalStr)
|
||||||
|
d := sha256.Sum256([]byte(finalStr))
|
||||||
|
signature, _ := rsa.SignPKCS1v15(rand.Reader, a.privateKey, crypto.SHA256, d[:])
|
||||||
|
sign = base64.StdEncoding.EncodeToString(signature)
|
||||||
|
return sign
|
||||||
|
}
|
||||||
|
|
||||||
|
func method2ResponseKey(method string) (responseKey string) {
|
||||||
|
responseKey = strings.Join(append(strings.Split(method, "."), "response"), "_")
|
||||||
|
return responseKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) AccessAPI(method string, params, bizContent map[string]interface{}) (retVal map[string]interface{}, err error) {
|
||||||
|
params = utils.MergeMaps(map[string]interface{}{
|
||||||
|
"app_id": a.GetAppID(),
|
||||||
|
"method": method,
|
||||||
|
"format": "JSON",
|
||||||
|
// "return_url"
|
||||||
|
"charset": "utf-8",
|
||||||
|
"sign_type": "RSA2",
|
||||||
|
"version": "1.0",
|
||||||
|
}, params)
|
||||||
|
if len(bizContent) > 0 {
|
||||||
|
params["biz_content"] = string(utils.MustMarshal(bizContent))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = platformapi.AccessPlatformAPIWithRetry(a.client,
|
||||||
|
func() *http.Request {
|
||||||
|
params["timestamp"] = utils.GetCurTimeStr()
|
||||||
|
params[signKey] = a.signParams(params)
|
||||||
|
fullURL := utils.GenerateGetURL(prodURL, "", params)
|
||||||
|
request, _ := http.NewRequest(http.MethodGet, fullURL, nil)
|
||||||
|
// request, _ := http.NewRequest(http.MethodPost, prodURL, bytes.NewReader(utils.MustMarshal(params)))
|
||||||
|
return request
|
||||||
|
},
|
||||||
|
a.config,
|
||||||
|
func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
|
||||||
|
if jsonResult1 == nil {
|
||||||
|
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
|
||||||
|
}
|
||||||
|
if errorResponse, ok := jsonResult1["error_response"].(map[string]interface{}); ok {
|
||||||
|
retVal = errorResponse
|
||||||
|
} else {
|
||||||
|
retVal, _ = jsonResult1[method2ResponseKey(method)].(map[string]interface{})
|
||||||
|
if retVal == nil {
|
||||||
|
return platformapi.ErrLevelGeneralFail, fmt.Errorf("结果格式异常")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errCode := utils.Interface2String(retVal["code"])
|
||||||
|
if errCode != CommonErrSuccess && errCode != "" {
|
||||||
|
err = utils.NewErrorCode(utils.Interface2String(retVal["msg"]), errCode)
|
||||||
|
if commonCanRetryErrMap[errCode] {
|
||||||
|
return platformapi.ErrLevelRecoverableErr, err
|
||||||
|
}
|
||||||
|
errLevel = platformapi.ErrLevelGeneralFail
|
||||||
|
}
|
||||||
|
subErrCode := utils.Interface2String(retVal["sub_code"])
|
||||||
|
if subErrCode != "" {
|
||||||
|
return platformapi.ErrLevelCodeIsNotOK, utils.NewErrorCode(utils.Interface2String(retVal["sub_msg"]), subErrCode)
|
||||||
|
} else if err != nil {
|
||||||
|
return errLevel, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return platformapi.ErrLevelSuccess, nil
|
||||||
|
})
|
||||||
|
return retVal, err
|
||||||
|
}
|
||||||
22
platformapi/alipayapi/alipayapi_test.go
Normal file
22
platformapi/alipayapi/alipayapi_test.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package alipayapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.rosy.net.cn/baseapi"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
api *API
|
||||||
|
sugarLogger *zap.SugaredLogger
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
logger, _ := zap.NewDevelopment()
|
||||||
|
sugarLogger = logger.Sugar()
|
||||||
|
baseapi.Init(sugarLogger)
|
||||||
|
|
||||||
|
api = New("2019110769024042", []byte(`
|
||||||
|
MIIEpAIBAAKCAQEAnsbBe0lrK5c4/xhb7ZLDWjGRWmIaj7HyV4LQ9X4EcTV5I5IKLezH1YaNLXytD/VXc5NsJp9IDTFLyOYdXee8lJxAeSQbuBBy1+xLd6qK2JQdVUGP3RZ0pAwVZSc9m0JKj5pYEeA2lvgh4NhSfGEw4BdZacpiDjFWkrQYl+RZkl/eIH2w7sA4wXs/hLSnPiG0VRtLtyYzfGCQdEJNjP5PA6V6CJTd68qTytLnpuaTuVxIYHGGSNd08694b1wOuGpFv6YK+mZkfaGkFoEpp3gUhEQ05duKjNBY71f0ez/Fym7GQYdHNXlsIvCmGQzklkfvQkHj7+MvPpsME4PkqQjRgwIDAQABAoIBAHLzwzDXPtgYbBOEN0oRb43lRS8Cx+gxFRt2goK58c1kwYeXO/dz7loRSDUehs1++wmaOjrcJvYmMpAIykoqdMXDOop6MfdZMUxSr3C78DpNQc9v4BBZKal7diH9/wRhQkolnI2UnvE+RIjdFRsn4pLbVMja1ZMg9WTRLt0JXjAyQZus9pADWADK12OSEIHBvz7/+kiFpq0aM+KPMElQG/mSDg1ESmzfYEbXYmPoiMwU+9frtnprrNdG9h143pb7mdzbXTt/8DbmpFgCfKL7ItpsC3VcZFDsj1Sd3gewrU+FLifH6oPGHTiwEoHNIn5m0RdPVEFoQnQxZnqxzDVBVYECgYEA5zCnBZBLotumxVdIRwncAXKEV5nMHJV2NKVmAc20vHJTsmI4/kA9B2Bjx9jzwwctBzFp1pIadccSbFO48Z5Hn0NdwYOnqba9W50n6R7wO3SnqQuCaoyTAvfkcjrZjZqq88Opa9tKGjD69MFFa+mnK7O7s8B7X6hCa/h80s0zDmkCgYEAr9C5yACb0haAp1WkuYf0B2TyPIofhYOXsjHcJqref+mDHgXSqPntYsXl/RVpJJSAGXJ/CnPd+jHQ0Fis2LuNpZ6ntYzcGoTQtnXx8BdQsnyEjyAvzxWv2JJV12zoSTEW7HL078qqEgbzmort6A8edRiv0kIoNf054QAtv/C9OwsCgYBPATVSlWkDkoR/U8CDZj8kz3miZhB2hC0M+KjPXPiynW80upQ3bsRsTOhMVzuWHlGo7533kZ4xOYJ2OnYtO6XGK0NS6ibVvHkhYadN5yC5cLgK8L/0oW1rykLrNmk6FuzsuKShEyNTqAFauuF6azKRoK44U0LWAa4RL62YbD9SYQKBgQCD0Qp5WXt6WES9MQj/0V607IpxuV1IzRC/GYLlutZ3MKyNpe/7oObKV3XH+nWKZ4xjh+SYAac8Hn1guBtfo77fncQ/6gxcFZgmNOfgCpsGNzVr2cX+jVP6HD0f9xdxSMzXGplp75jzSyL5i5AznKJJSOkJy3A6ilEK0Qd8ERLPYQKBgQC/QSV0c71x3nYz3koOQv7s36i5R0jeHnadSMyGUlrYmn/TaXj0KaUaEYRcgJyWB/dxy3cde8EKlqg0q80Zc6ExkZKhpO6k1lj9Bta+l+KAyVFroYDIy/b0Wukr2qV1mkMK0FQ0X2hVbv6TJBq5RMNeYAy1shOeWIwaS5muSYm4Ig==
|
||||||
|
`))
|
||||||
|
}
|
||||||
29
platformapi/alipayapi/member.go
Normal file
29
platformapi/alipayapi/member.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package alipayapi
|
||||||
|
|
||||||
|
import "git.rosy.net.cn/baseapi/utils"
|
||||||
|
|
||||||
|
type UserInfo struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Avatar string `json:"avatar"`
|
||||||
|
City string `json:"city"`
|
||||||
|
Gender string `json:"gender"`
|
||||||
|
IsCertified string `json:"is_certified"`
|
||||||
|
IsStudentCertified string `json:"is_student_certified"`
|
||||||
|
NickName string `json:"nick_name"`
|
||||||
|
Province string `json:"province"`
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
UserStatus string `json:"user_status"`
|
||||||
|
UserType string `json:"user_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) UserInfoShare(accessToken string) (userInfo *UserInfo, err error) {
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"auth_token": accessToken,
|
||||||
|
}
|
||||||
|
retVal, err := a.AccessAPI("alipay.user.info.share", params, nil)
|
||||||
|
if err == nil {
|
||||||
|
err = utils.Map2StructByJson(retVal, &userInfo, false)
|
||||||
|
}
|
||||||
|
return userInfo, err
|
||||||
|
}
|
||||||
11
platformapi/alipayapi/member_test.go
Normal file
11
platformapi/alipayapi/member_test.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package alipayapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUserInfoShare(t *testing.T) {
|
||||||
|
result, err := api.UserInfoShare("authusrBbe61f93632264c44b4e2f5da25267C98")
|
||||||
|
t.Log(err)
|
||||||
|
t.Log(result)
|
||||||
|
}
|
||||||
49
platformapi/alipayapi/utils.go
Normal file
49
platformapi/alipayapi/utils.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package alipayapi
|
||||||
|
|
||||||
|
import "git.rosy.net.cn/baseapi/utils"
|
||||||
|
|
||||||
|
const (
|
||||||
|
GrantTypeCode = "authorization_code"
|
||||||
|
GrantTypeRefresh = "refresh_token"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TokenInfo struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
AlipayUserID string `json:"alipay_user_id"`
|
||||||
|
ExpiresIn int64 `json:"expires_in"`
|
||||||
|
ReExpiresIn int64 `json:"re_expires_in"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) UserInfoAuth(scopes []string, state string) (retVal map[string]interface{}, err error) {
|
||||||
|
retVal, err = a.AccessAPI("alipay.user.info.auth", nil, map[string]interface{}{
|
||||||
|
"scopes": scopes,
|
||||||
|
"state": state,
|
||||||
|
})
|
||||||
|
return retVal, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) AuthTokenAppQuery(appAuthToken string) (retVal map[string]interface{}, err error) {
|
||||||
|
retVal, err = a.AccessAPI("alipay.open.auth.token.app.query", nil, map[string]interface{}{
|
||||||
|
"app_auth_token": appAuthToken,
|
||||||
|
})
|
||||||
|
return retVal, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) SystemAuthToken(grantType, code, refreshToken string) (tokenInfo *TokenInfo, err error) {
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"grant_type": grantType,
|
||||||
|
}
|
||||||
|
if code != "" {
|
||||||
|
params["code"] = code
|
||||||
|
}
|
||||||
|
if refreshToken != "" {
|
||||||
|
params["refresh_token"] = refreshToken
|
||||||
|
}
|
||||||
|
retVal, err := a.AccessAPI("alipay.system.oauth.token", params, nil)
|
||||||
|
if err == nil {
|
||||||
|
err = utils.Map2StructByJson(retVal, &tokenInfo, false)
|
||||||
|
}
|
||||||
|
return tokenInfo, err
|
||||||
|
}
|
||||||
11
platformapi/alipayapi/utils_test.go
Normal file
11
platformapi/alipayapi/utils_test.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package alipayapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSystemAuthToken(t *testing.T) {
|
||||||
|
result, err := api.SystemAuthToken(GrantTypeCode, "c91ed60bebae473b9507a08e0c86NE98", "")
|
||||||
|
t.Log(err)
|
||||||
|
t.Log(result)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user