Просмотр исходного кода

add alipay verify by alipayCertPublicKey_RSA2.crt

Xiaodan.C 6 лет назад
Родитель
Сommit
720d9406a8
3 измененных файлов с 142 добавлено и 9 удалено
  1. 39 7
      alipay/client_test.go
  2. 81 0
      alipay/service_api.go
  3. 22 2
      examples/alipay/alipay_ServiceApi.go

+ 39 - 7
alipay/client_test.go

@@ -25,14 +25,14 @@ func TestMain(m *testing.M) {
 	// 配置公共参数
 	client.SetCharset("utf-8").
 		SetSignType("RSA2").
-		//SetReturnUrl("https://www.gopay.ink").
+		// SetReturnUrl("https://www.gopay.ink").
 		SetNotifyUrl("https://www.gopay.ink")
 
-	//err := client.SetCertSnByPath("cert/appCertPublicKey.crt", "cert/alipayRootCert.crt", "cert/alipayCertPublicKey_RSA2.crt")
-	//if err != nil {
+	// err := client.SetCertSnByPath("cert/appCertPublicKey.crt", "cert/alipayRootCert.crt", "cert/alipayCertPublicKey_RSA2.crt")
+	// if err != nil {
 	//	fmt.Println("SetCertSnByPath:", err)
 	//	return
-	//}
+	// }
 
 	os.Exit(m.Run())
 }
@@ -242,7 +242,7 @@ func TestClient_SystemOauthToken(t *testing.T) {
 }
 
 func TestClient_TradeOrderSettle(t *testing.T) {
-	//请求参数
+	// 请求参数
 	bm := make(gopay.BodyMap)
 	bm.Set("out_request_no", "201907301518083384")
 	bm.Set("trade_no", "2019072522001484690549776067")
@@ -251,7 +251,7 @@ func TestClient_TradeOrderSettle(t *testing.T) {
 	listParams = append(listParams, OpenApiRoyaltyDetailInfoPojo{"transfer", "2088802095984694", "userId", "userId", "2088102363632794", "0.01", "分账给2088102363632794"})
 
 	bm.Set("royalty_parameters", listParams)
-	//fmt.Println("listParams:", bm.Get("royalty_parameters"))
+	// fmt.Println("listParams:", bm.Get("royalty_parameters"))
 
 	// 发起交易结算接口
 	aliRsp, err := client.TradeOrderSettle(bm)
@@ -313,7 +313,7 @@ func TestClient_FundTransToaccountTransfer(t *testing.T) {
 }
 
 func TestClient_UserCertifyOpenInit(t *testing.T) {
-	//请求参数
+	// 请求参数
 	bm := make(gopay.BodyMap)
 	bm.Set("outer_order_no", "ZGYD201809132323000001234")
 	// 认证场景码:FACE:多因子人脸认证,CERT_PHOTO:多因子证照认证,CERT_PHOTO_FACE :多因子证照和人脸认证,SMART_FACE:多因子快捷认证
@@ -449,6 +449,38 @@ func TestVerifySign(t *testing.T) {
 	fmt.Println("OK:", ok)
 }
 
+func TestVerifySignWithCert(t *testing.T) {
+	// 测试,假数据,无法验签通过
+	bm := make(gopay.BodyMap)
+	bm.Set("sign", "kPbQIjX+xQc8F0/A6/AocELIjhhZnGbcBN6G4MM/HmfWL4ZiHM6fWl5NQhzXJusaklZ1LFuMo+lHQUELAYeugH8LYFvxnNajOvZhuxNFbN2LhF0l/KL8ANtj8oyPM4NN7Qft2kWJTDJUpQOzCzNnV9hDxh5AaT9FPqRS6ZKxnzM=")
+	bm.Set("sign_type", "RSA2")
+	bm.Set("total_amount", "2.00")
+	bm.Set("buyer_id", "2088102116773037")
+	bm.Set("body", "大乐透2.1")
+	bm.Set("trade_no", "2016071921001003030200089909")
+	bm.Set("refund_fee", "0.00")
+	bm.Set("notify_time", "2016-07-19 14:10:49")
+	bm.Set("subject", "大乐透2.1")
+	bm.Set("charset", "utf-8")
+	bm.Set("notify_type", "trade_status_sync")
+	bm.Set("out_trade_no", "0719141034-6418")
+	bm.Set("gmt_close", "2016-07-19 14:10:46")
+	bm.Set("gmt_payment", "2016-07-19 14:10:47")
+	bm.Set("trade_status", "TRADE_SUCCESS")
+	bm.Set("version", "1.0")
+	bm.Set("gmt_create", "2016-07-19 14:10:44")
+	bm.Set("app_id", "2015102700040153")
+	bm.Set("seller_id", "2088102119685838")
+	bm.Set("notify_id", "4a91b7a78a503640467525113fb7d8bg8e")
+
+	ok, err := VerifySignWithCert("/cert/alipayCertPublicKey_RSA2.crt", bm)
+	if err != nil {
+		fmt.Println("err:", err)
+		return
+	}
+	fmt.Println("OK:", ok)
+}
+
 func TestGetCertSN(t *testing.T) {
 	sn, err := GetCertSN("cert/alipayCertPublicKey_RSA2.crt")
 	if err != nil {

+ 81 - 0
alipay/service_api.go

@@ -232,6 +232,87 @@ func verifySign(signData, sign, signType, aliPayPublicKey string) (err error) {
 	return rsa.VerifyPKCS1v15(publicKey, hashs, h.Sum(nil), signBytes)
 }
 
+// VerifySignWithCert 支付宝异步通知验签
+//    注意:APP支付,手机网站支付,电脑网站支付 暂不支持同步返回验签
+//    aliPayPublicKeyPath:支付宝公钥存放路径 alipayCertPublicKey_RSA2.crt
+//    bean:此参数为异步通知解析的结构体或BodyMap:notifyReq 或 bm
+//    返回参数ok:是否验签通过
+//    返回参数err:错误信息
+//    验签文档:https://docs.open.alipay.com/200/106120
+func VerifySignWithCert(aliPayPublicKeyPath string, bean interface{}) (ok bool, err error) {
+	if bean == nil {
+		return false, errors.New("bean is nil")
+	}
+	var (
+		bodySign     string
+		bodySignType string
+		signData     string
+		bm           = make(gopay.BodyMap)
+	)
+	if reflect.ValueOf(bean).Kind() == reflect.Map {
+		if bm, ok = bean.(gopay.BodyMap); ok {
+			bodySign = bm.Get("sign")
+			bodySignType = bm.Get("sign_type")
+			bm.Remove("sign")
+			bm.Remove("sign_type")
+			signData = bm.EncodeAliPaySignParams()
+		}
+	} else {
+		bs, err := json.Marshal(bean)
+		if err != nil {
+			return false, fmt.Errorf("json.Marshal:%w", err)
+		}
+		if err = json.Unmarshal(bs, &bm); err != nil {
+			return false, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err)
+		}
+		bodySign = bm.Get("sign")
+		bodySignType = bm.Get("sign_type")
+		bm.Remove("sign")
+		bm.Remove("sign_type")
+		signData = bm.EncodeAliPaySignParams()
+	}
+	if err = verifySignCert(signData, bodySign, bodySignType, aliPayPublicKeyPath); err != nil {
+		return false, err
+	}
+	return true, nil
+}
+
+func verifySignCert(signData, sign, signType, aliPayPublicKeyPath string) (err error) {
+	var (
+		h         hash.Hash
+		hashs     crypto.Hash
+		block     *pem.Block
+		pubKey    *x509.Certificate
+		publicKey *rsa.PublicKey
+		ok        bool
+		bytes     []byte
+	)
+	if bytes, err = ioutil.ReadFile(aliPayPublicKeyPath); err != nil {
+		return fmt.Errorf("支付宝公钥文件读取失败: %w", err)
+	}
+	signBytes, _ := base64.StdEncoding.DecodeString(sign)
+	if block, _ = pem.Decode(bytes); block == nil {
+		return errors.New("支付宝公钥Decode错误")
+	}
+	if pubKey, err = x509.ParseCertificate(block.Bytes); err != nil {
+		return fmt.Errorf("x509.ParseCertificate:%w", err)
+	}
+	if publicKey, ok = pubKey.PublicKey.(*rsa.PublicKey); !ok {
+		return errors.New("支付宝公钥转换错误")
+	}
+	switch signType {
+	case "RSA":
+		hashs = crypto.SHA1
+	case "RSA2":
+		hashs = crypto.SHA256
+	default:
+		hashs = crypto.SHA256
+	}
+	h = hashs.New()
+	h.Write([]byte(signData))
+	return rsa.VerifyPKCS1v15(publicKey, hashs, h.Sum(nil), signBytes)
+}
+
 // FormatPrivateKey 格式化 普通应用秘钥
 func FormatPrivateKey(privateKey string) (pKey string) {
 	var buffer strings.Builder

+ 22 - 2
examples/alipay/alipay_ServiceApi.go

@@ -64,7 +64,7 @@ func VerifySyncSign() {
 func ParseNotifyResultAndVerifySign(req *http.Request) {
 	aliPayPublicKey := "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1wn1sU/8Q0rYLlZ6sq3enrPZw2ptp6FecHR2bBFLjJ+sKzepROd0bKddgj+Mr1ffr3Ej78mLdWV8IzLfpXUi945DkrQcOUWLY0MHhYVG2jSs/qzFfpzmtut2Cl2TozYpE84zom9ei06u2AXLMBkU6VpznZl+R4qIgnUfByt3Ix5b3h4Cl6gzXMAB1hJrrrCkq+WvWb3Fy0vmk/DUbJEz8i8mQPff2gsHBE1nMPvHVAMw1GMk9ImB4PxucVek4ZbUzVqxZXphaAgUXFK2FSFU+Q+q1SPvHbUsjtIyL+cLA6H/6ybFF9Ffp27Y14AHPw29+243/SpMisbGcj2KD+evBwIDAQAB"
 
-	//解析请求参数
+	// 解析请求参数
 	notifyReq, err := alipay.ParseNotifyResult(req)
 	if err != nil {
 		fmt.Println("err:", err)
@@ -72,7 +72,7 @@ func ParseNotifyResultAndVerifySign(req *http.Request) {
 	}
 	fmt.Println("notifyReq:", *notifyReq)
 
-	//验签
+	// 验签
 	ok, err := alipay.VerifySign(aliPayPublicKey, notifyReq)
 	if err != nil {
 		fmt.Println("err:", err)
@@ -81,6 +81,26 @@ func ParseNotifyResultAndVerifySign(req *http.Request) {
 	log.Println("支付宝验签是否通过:", ok)
 }
 
+func ParseNotifyResultAndVerifySignWithCert(req *http.Request) {
+	aliPayPublicKeyPath := "/root/alipay/cert/alipayCertPublicKey_RSA2.crt"
+
+	// 解析请求参数
+	notifyReq, err := alipay.ParseNotifyResult(req)
+	if err != nil {
+		fmt.Println("err:", err)
+		return
+	}
+	fmt.Println("notifyReq:", *notifyReq)
+
+	// 验签
+	ok, err := alipay.VerifySignWithCert(aliPayPublicKeyPath, notifyReq)
+	if err != nil {
+		fmt.Println("err:", err)
+		return
+	}
+	log.Println("支付宝验签是否通过:", ok)
+}
+
 func GetCertSN() {
 	sn, err := alipay.GetCertSN("cert/appCertPublicKey.crt")
 	if err != nil {