您现在的位置是:网站首页> 编程资料编程资料

golang实现京东支付v2版本的示例代码_Golang_

2023-05-26 365人已围观

简介 golang实现京东支付v2版本的示例代码_Golang_

一、准备阶段

 pc&h5 接入步骤

官方文档 https://payapi.jd.com/docList...

查看主要接入步骤

密钥生成

• 需要设置desc key

• md5 key 和 app id app对接会使用

• 证书文件名称

 my_rsa_private_pkcs8_key.pem wy_rsa_public_key.pem

示例程序使用私钥格式为 pkcs8 格式

官方的SDK中的数据可以在示例程序中使用

下载SDK地址 https://payapi.jd.com/docList...

找到接口文档中的Demo

还会用到的包

 import ( "encoding/base64" "encoding/json" "encoding/xml" "errors" "fmt" "io/ioutil" "net/http" "os" "strconv" "strings" "time" )

加密、解密、验证签名

 package main import ( "bytes" "crypto" "crypto/des" cryptoRand "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/hex" "encoding/pem" "errors" "fmt" "math/rand" "regexp" "sort" "strings" "time" ) func randNumber() string { return fmt.Sprintf("%05v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(100000)) } func checkSign(decryptBytes []byte, sign, publicKey string) bool { decrypt := string(decryptBytes) clipStartIndex := strings.Index(decrypt, "") clipEndIndex := strings.Index(decrypt, "") xmlStart := decrypt[0:clipStartIndex] xmlEnd := decrypt[clipEndIndex+7 : len(decrypt)] originXml := xmlStart + xmlEnd //签名校验 if sign == "" { return false } return checkRsaSign(originXml, publicKey, sign) } func replaceXmlStrBlankChar(str string) string { str = strings.Replace(str, "\r", "", -1) str = strings.Replace(str, "\n", "", -1) str = strings.Replace(str, "\t", "", -1) reg, _ := regexp.Compile(">\\s+<") str = reg.ReplaceAllString(str, "><") reg, _ = regexp.Compile("\\s+\\/>") str = reg.ReplaceAllString(str, "/>") return str } func getPaySign(paramMap map[string]string, privateKey string) (string, error) { payString := getSortString(paramMap) return getRsaSign(payString, privateKey) } // ------ // 加密 func encrypt3DES(paramMap map[string]string, desKey string) (map[string]string, error) { desKey = base64DecodeStr(desKey) for k, v := range paramMap { if k == "sign" || k == "merchant" || k == "version" { continue } encrypt, err := tripleEcbDesEncrypt([]byte(v), []byte(desKey)) if err != nil { return paramMap, err } paramMap[k] = decimalByteSlice2HexString(encrypt) } return paramMap, nil } func decryptArg(notifyQuery NotifyQuery, desKey string) (decryptBytes []byte, err error) { desKeyBytes, err := base64.StdEncoding.DecodeString(desKey) if err != nil { return nil, err } encryptBytes, err := base64.StdEncoding.DecodeString(notifyQuery.Encrypt) if err != nil { return nil, err } encryptBytes, err = hexString2Bytes(string(encryptBytes)) if err != nil { return nil, err } decryptBytes, err = tripleEcbDesDecrypt(encryptBytes, desKeyBytes) if err != nil { return nil, err } return decryptBytes, nil } // JDAPP填充规则 func jdPadding(origData []byte) []byte { merchantData := len(origData) x := (merchantData + 4) % 8 y := 0 if x == 0 { y = 0 } else { y = 8 - x } sizeByte := integerToBytes(merchantData) var resultByte []byte //填充byte数据长度 for i := 0; i < 4; i++ { resultByte = append(resultByte, sizeByte[i]) } //填充原数据长度 for j := 0; j < merchantData; j++ { resultByte = append(resultByte, origData[j]) } //填充0 for k := 0; k < y; k++ { resultByte = append(resultByte, 0x00) } return resultByte } func jdUnPadding(unPaddingResult []byte) []byte { var Result []byte var dataSizeByte []byte for i := 0; i < 4; i++ { dataSizeByte = append(dataSizeByte, unPaddingResult[i]) } decimalDataSize := byteArrayToInt(dataSizeByte) for j := 0; j < decimalDataSize; j++ { Result = append(Result, unPaddingResult[4+j]) } return Result } // 字节数组表示的实际长度 func byteArrayToInt(dataSizeByte []byte) int { value := 0 for i := 0; i < 4; i++ { shift := byte((4 - 1 - i) * 8) value = value + int(dataSizeByte[i]&0x000000FF)<> 24 & 0xff) byt[1] = byte(val >> 16 & 0xff) byt[2] = byte(val >> 8 & 0xff) byt[3] = byte(val & 0xff) return byt } // byte转16进制字符串 func decimalByteSlice2HexString(DecimalSlice []byte) string { var sa = make([]string, 0) for _, v := range DecimalSlice { sa = append(sa, fmt.Sprintf("%02X", v)) } ss := strings.Join(sa, "") return ss } // 十六进制字符串转byte func hexString2Bytes(str string) ([]byte, error) { Bys, err := hex.DecodeString(str) if err != nil { return nil, err } return Bys, nil } // base解码 func base64DecodeStr(src string) string { a, err := base64.StdEncoding.DecodeString(src) if err != nil { return "" } return string(a) } // Des解密 func decrypt(crypted, key []byte) ([]byte, error) { if len(crypted) < 1 || len(key) < 1 { return nil, errors.New("wrong data or key") } block, err := des.NewCipher(key) if err != nil { return nil, err } out := make([]byte, len(crypted)) dst := out bs := block.BlockSize() if len(crypted)%bs != 0 { return nil, errors.New("wrong crypted size") } for len(crypted) > 0 { block.Decrypt(dst, crypted[:bs]) crypted = crypted[bs:] dst = dst[bs:] } return out, nil } // [golang ECB 3DES Decrypt] func tripleEcbDesDecrypt(crypted, key []byte) ([]byte, error) { tkey := make([]byte, 24, 24) copy(tkey, key) k1 := tkey[:8] k2 := tkey[8:16] k3 := tkey[16:] buf1, err := decrypt(crypted, k3) if err != nil { return nil, err } buf2, err := encrypt(buf1, k2) if err != nil { return nil, err } out, err := decrypt(buf2, k1) if err != nil { return nil, err } out = jdUnPadding(out) return out, nil } // sha256加密 func hasha256(str string) string { h := sha256.New() h.Write([]byte(str)) cipherStr := h.Sum(nil) //return cipherStr return hex.EncodeToString(cipherStr) } // base解编码 func base64EncodeStr(src string) string { return base64.StdEncoding.EncodeToString([]byte(src)) } // 对消息的散列值进行数字签名 func signPKCS1v15(msg, privateKey []byte, hashType crypto.Hash) ([]byte, error) { block, _ := pem.Decode(privateKey) if block == nil { return nil, errors.New("private key format error") } pri, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { return nil, errors.New("parse private key error") } key, ok := pri.(*rsa.PrivateKey) if ok == false { return nil, errors.New("private key format error") } sign, err := rsa.SignPKCS1v15(cryptoRand.Reader, key, hashType, msg) if err != nil { return nil, errors.New("sign error") } return sign, nil } // Des加密 func encrypt(origData, key []byte) ([]byte, error) { if len(origData) < 1 || len(key) < 1 { return nil, errors.New("wrong data or key") } block, err := des.NewCipher(key) if err != nil { return nil, err } bs := block.BlockSize() if len(origData)%bs != 0 { return nil, errors.New("wrong padding") } out := make([]byte, len(origData)) dst := out for len(origData) > 0 { block.Encrypt(dst, origData[:bs]) origData = origData[bs:] dst = dst[bs:] } return out, nil } // [golang ECB 3DES Encrypt] func tripleEcbDesEncrypt(origData, key []byte) ([]byte, error) { tkey := make([]byte, 24, 24) copy(tkey, key) k1 := tkey[:8] k2 := tkey[8:16] k3 := tkey[16:] origData = jdPadding(origData) // PKCS5Padding(origData, bs) buf1, err := encrypt(origData, k1) if err != nil { return nil, err } buf2, err := decrypt(buf1, k2) if err != nil { return nil, err } out, err := encrypt(buf2, k3) if err != nil { return nil, err } return out, nil } // ------------ // 验证签名 func verifyPKCS1v15(msg, sign, publicKey []byte, hashType crypto.Hash) bool { block, _ := pem.Decode(publicKey) if block == nil { return false } pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { panic(err) } err = rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), hashType, msg, sign) return err == nil } func getRsaSign(paramStr string, privateKey string) (string, error) { sha256Str := hasha256(paramStr) sign, err := signPKCS1v15([]byte(sha256Str), []byte(privateKey), crypto.Hash(0)) if err != nil { return "", err } base64String := base64.StdEncoding.EncodeToString(sign) return base64String, nil } func checkRsaSign(paramStr string, publicKey, sign string) bool { signByte, err := base64.StdEncoding.DecodeString(sign) if err != nil { return false } sha256Str := hasha256(paramStr) return verifyPKCS1v15([]byte(sha256Str), signByte, []byte(publicKey), crypto.Hash(0)) } // ------- // 字符串拼接 // 支付字符串拼接 func getSortString(m map[string]string) string { var buf bytes.Buffer keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { vs := m[k] if buf.Len() > 0 { buf.WriteByte('&') } buf.WriteString(k) buf.WriteByte('=') buf.WriteString(vs) } return buf.String() }

程序中加载密钥

 func getKey(keyType string) (string, error) { keyMap := map[string]string{ "private_key": "./private.pem", "public_key": "./public.pem", } path, ok := keyMap[keyType] if !ok { return "", errors.New("key path not exists") } fileHandler, err := os.Open(path) if err != nil { return "", err } defer fileHandler.Close() keyBytes, err := ioutil.ReadAll(fileHandler) if err != nil { return "", err } return string(keyBytes), nil }

二、发起支付

常量

 常量 const version = "V2.0" // 京东支付版本 const merchantId = "" // 商户id const desKey = "" // desc key const timeLayout = "20060102150405" const cny = "CNY" const practicalityGoodsType = "GT01" //商品类型-实物 const businessServiceConsumeCode = "100001" const practicality = "0" //商品类型-实物

调用在线支付接口

pc h5 发起支付

官方文档 https://payapi.jd.com/docList...

 type Order struct { OrderId string `json:"order_id"` Amount float64 `json:"amount"` Items []*OrderItem `json:"items"` ShippingAddress *OrderShippingAddress `json:"shipping_address"` } type OrderItem struct { GoodsNo string `json:"goods_no"` GoodsName string `json:"goods_name"` GoodsPrice float64 `json:"goods_price"` GoodsNum uint32 `json:"goods_num"` } type OrderShippingAddress struct { Name string `json:"name"` Mobile string `json:"mobile"` Address string `json:"address"` Province string `json:
                
                

-六神源码网