Browse Source

增加招行支付通用函数库

master v0.5.0
lijianbin 2 years ago
parent
commit
a28b3cd384
2 changed files with 430 additions and 0 deletions
  1. +402
    -0
      cmb.go
  2. +28
    -0
      go.sum

+ 402
- 0
cmb.go View File

@ -0,0 +1,402 @@
package helper
import (
"bytes"
"encoding/base64"
"encoding/hex"
"errors"
"git.tetele.net/tgo/crypter"
"github.com/ZZMarquis/gm/sm2"
"github.com/ZZMarquis/gm/sm3"
jsoniter "github.com/json-iterator/go"
"io/ioutil"
"log"
"math/big"
"net/http"
"reflect"
"sort"
"strings"
"time"
)
var json = jsoniter.ConfigCompatibleWithStandardLibrary
// 合并map数据
func MergeMapData(x, y map[string]interface{}) map[string]interface{} {
n := make(map[string]interface{})
for i, v := range x {
for j, w := range y {
if i == j {
n[i] = w
} else {
if _, ok := n[i]; !ok {
n[i] = v
}
if _, ok := n[j]; !ok {
n[j] = w
}
}
}
}
return n
}
// 针对传参为json或者数组类型的字段,进行字符串排序
func HttpBuildSort(data map[string]interface{}) string {
keySlice := []string{}
for k, _ := range data {
keySlice = append(keySlice, k)
}
// 排序字符串
sort.Strings(keySlice)
res := make(map[string]interface{}, 0)
for _, value := range keySlice {
data_val := ToStr(data[value])
if value != "" && data_val != "" {
res[value] = data_val
}
}
res_byte, _ := json.Marshal(res)
return string(res_byte)
}
// body参数处理
func FormatBodyData(body map[string]interface{}) map[string]interface{} {
data := map[string]interface{}{}
if len(body) > 0 {
for k, v := range body {
typeOfA := reflect.TypeOf(v)
if typeOfA.Kind().String() == "map" {
build_str_format, _ := InterfaceToMapInterface(v)
if len(build_str_format) < 1 {
continue
}
// json键值对处理
data[k] = HttpBuildSort(build_str_format)
// log.Println("排序后的数据: ", data[k])
} else if typeOfA.Kind().String() == "slice" {
val_slice := []interface{}{}
// json键值对处理
for _, val_inter := range v.([]interface{}) {
val_map, _ := InterfaceToMapInterface(val_inter)
each_val := HttpBuildSort(val_map)
val_slice = append(val_slice, each_val)
}
if len(val_slice) < 1 {
continue
}
data[k] = val_slice
// log.Println("排序后的数据: ", data[k])
} else {
data[k] = v
}
}
}
return data
}
// 字符串排序拼接
func CmbHttpBuildQuery(data map[string]interface{}, filter_sign bool) string {
keySlice := []string{}
// 剔除sign字段
for k, _ := range data {
if filter_sign && k == "sign" {
continue
}
keySlice = append(keySlice, k)
}
// 排序字符串
sort.Strings(keySlice)
var query string
for _, value := range keySlice {
if value != "" && data[value] != "" {
query += StringJoin(value, "=", ToStr(data[value]), "&")
}
}
build_str := strings.Trim(query, "&")
log.Println("拼接后的数据: ", build_str)
return build_str
}
// 生成签名sign--聚合支付
func SetSign(data map[string]interface{}, privateKey string) string {
log.Println("招行加签start")
build_str := CmbHttpBuildQuery(data, true)
priv := new(sm2.PrivateKey)
priv.Curve = sm2.GetSm2P256V1()
dBytes, _ := hex.DecodeString(privateKey)
priv.D = new(big.Int).SetBytes(dBytes)
signature, err := sm2.Sign(priv, []byte("1234567812345678"), []byte(build_str))
if err != nil {
log.Println("国密加密异常", err)
return ""
}
sign := base64.StdEncoding.EncodeToString(signature)
log.Println("加密后sign值: ", sign)
log.Println("招行加签end")
return sign
}
// 创建请求头信息--聚合支付
func HeaderInfo(appid, secret, sign string) map[string]string {
if appid == "" || secret == "" || sign == "" {
return map[string]string{}
}
headerData := map[string]string{}
headerData["appid"] = appid
headerData["sign"] = sign
headerData["secret"] = secret
headerData["timestamp"] = ToStr(time.Now().Unix())
build_str := CmbHttpBuildQuery(MapStringToInterface(headerData), false)
headerData["apisign"] = crypter.Md5Str(build_str)
delete(headerData, "sign")
delete(headerData, "secret")
log.Println("header信息", headerData)
return headerData
}
// 接口验签--各客户端请求我们接口验签
func CheckSign(appid, app_secret, timeStamp, nonce, sign string, body map[string]interface{}) error {
log.Println("请求验签start")
/*time_now := time.Now().Unix()
if time_now-ToInt64(timeStamp) > 10 {
return errors.New("请求时间超出范围,拒绝访问")
}*/
sign_info := map[string]interface{}{
"appid": appid,
"timestamp": timeStamp,
"nonce": nonce,
}
if len(body) > 0 {
body_format := FormatBodyDataNoList(body)
sign_info = MergeMapData(sign_info, body_format)
}
str := CmbHttpBuildQuery(sign_info, false) + "&" + app_secret
log.Println("加密前数据: ", str)
sign_str := crypter.Md5Str(str)
log.Println("加密后数据: ", sign_str)
if sign_str != sign {
return errors.New("签名不正确")
}
log.Println("请求验签end")
return nil
}
// post 请求
func PostJsonData(url string, param interface{}, headerinfo map[string]string) ([]byte, error) {
httpClient := &http.Client{}
params, err := json.Marshal(param)
if err != nil {
return []byte(""), err
}
log.Println(bytes.NewBuffer(params))
req, err := http.NewRequest("POST", url, bytes.NewBuffer(params))
if err != nil {
return []byte(""), err
}
req.Header.Set("Content-Type", "application/json")
if len(headerinfo) > 0 {
for k, v := range headerinfo {
req.Header[k] = []string{v}
}
}
resp, err := httpClient.Do(req)
if err != nil {
return []byte(""), err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return []byte(""), err
}
return body, nil
}
func SetSignsm3(data map[string]interface{}) string {
build_str := HttpBuildjson(data, false)
h := sm3.New()
h.Write([]byte(build_str))
sum := h.Sum(nil)
sign := hex.EncodeToString(sum)
return sign
}
func CashierHeaderInfoCompany(appid, secret, sign, private_key string) map[string]string {
if appid == "" || secret == "" || sign == "" || private_key == "" {
return map[string]string{}
}
headerData := map[string]string{}
headerData["appid"] = appid
headerData["sign"] = sign
headerData["secret"] = secret
headerData["timestamp"] = ToStr(time.Now().Unix())
headerData["apisign"] = SetSignhex(headerData, private_key)
headerData["verify"] = "SM3withSM2"
delete(headerData, "secret")
return headerData
}
// 生成签名sign
func SetSignhex(data map[string]string, privateKey string) string {
build_str := CmbHttpBuildQuery(MapStringToInterface(data), false)
priv := new(sm2.PrivateKey)
priv.Curve = sm2.GetSm2P256V1()
dBytes, _ := hex.DecodeString(privateKey)
priv.D = new(big.Int).SetBytes(dBytes)
sign, _ := sm2.Sign(priv, []byte("1234567812345678"), []byte(build_str))
sign = SM2Asn1ToRaw(sign)
return hex.EncodeToString(sign)
}
func SM2Asn1ToRaw(data []byte) []byte {
i := 3
ret := []byte{}
if data[i] == 32 {
i = i + 1
} else if data[i] == 33 {
i = i + 2
}
for k := 0; k < 32; k++ {
ret = append(ret, data[i+k])
}
i = i + 32
i = i + 1
if data[i] == 32 {
i = i + 1
} else if data[i] == 33 {
i = i + 2
}
for k := 0; k < 32; k++ {
ret = append(ret, data[i+k])
}
return ret
}
// 字符串排序拼接
func HttpBuildjson(data map[string]interface{}, filter_sign bool) string {
keySlice := []string{}
res := map[string]interface{}{}
// 剔除sign字段
for k, _ := range data {
if filter_sign && k == "sign" {
continue
}
keySlice = append(keySlice, k)
}
// 排序字符串
sort.Strings(keySlice)
for _, value := range keySlice {
if value != "" && data[value] != "" {
res[value] = data[value]
}
}
ss, _ := json.Marshal(res)
log.Println("拼接后的数据: ", string(ss))
return string(ss)
}
// body参数处理
func FormatBodyDataNoList(body map[string]interface{}) map[string]interface{} {
data := map[string]interface{}{}
if len(body) > 0 {
for k, v := range body {
typeOfA := reflect.TypeOf(v)
if typeOfA.Kind().String() == "map" || typeOfA.Kind().String() == "slice" {
continue
} else {
if typeOfA.Kind().String() == "string" {
if ToStr(v) != "" {
data[k] = v
}
}
}
}
}
return data
}
// 聚合支付异步回调验签
func JhNotifyCheckSign(sign, public_key string, data map[string]string) bool {
build_sort_str := CmbHttpBuildQuery(MapStringToInterface(data), true)
pub_x := ""
pub_y := ""
// 私钥截取
if len(public_key) == 128 {
pub_x = public_key[:64]
pub_y = public_key[64:]
} else if len(public_key) == 130 && (public_key[:2] == "04") {
public_key = public_key[2:]
pub_x = public_key[:64]
pub_y = public_key[64:]
} else {
log.Println("异步验签公钥出错", public_key)
return false
}
sign_b64, _ := base64.StdEncoding.DecodeString(sign)
pub := new(sm2.PublicKey)
pub.Curve = sm2.GetSm2P256V1()
xBytes, _ := hex.DecodeString(pub_x)
yBytes, _ := hex.DecodeString(pub_y)
pub.X = new(big.Int).SetBytes(xBytes)
pub.Y = new(big.Int).SetBytes(yBytes)
result := sm2.Verify(pub, []byte("1234567812345678"), []byte(build_sort_str), sign_b64)
if !result {
return false
}
return true
}

+ 28
- 0
go.sum View File

@ -0,0 +1,28 @@
git.tetele.net/tgo/crypter v0.2.2 h1:YMQJh2Gj5Po4ZfelJUmXBKi01UbmtiSy3bmqRfnYQMo=
git.tetele.net/tgo/crypter v0.2.2/go.mod h1:vfvRLZA8+lHNgNXneOcgvVhDyuv25ZRb+C6xHOmXNx0=
github.com/ZZMarquis/gm v1.3.2 h1:lFtpzg5zeeVMZ/gKi0gtYcKLBEo9XTqsZDHDz6s3Gow=
github.com/ZZMarquis/gm v1.3.2/go.mod h1:wWbjZYgruQVd7Bb8UkSN8ujU931kx2XUW6nZLCiDE0Q=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

Loading…
Cancel
Save