+alipayapi

This commit is contained in:
gazebo
2020-01-08 18:05:08 +08:00
parent 94624d06ba
commit 3bf8e50858
6 changed files with 284 additions and 0 deletions

View 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
}

View 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==
`))
}

View 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
}

View 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)
}

View 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
}

View 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)
}