• 证书模式支付宝支付接口demo 沙箱


    1. go语言推荐使用第三方支付库 github.com/go-pay/gopay
    2. 说明
      1. 支付宝和应用都有公私钥,即2套,为什么是2套?
        1. 用户通过应用私钥加密发送消息给支付宝,支付宝通过应用公钥解密;
        2. 支付宝通过支付宝私钥加密发送消息给用户,用户通过支付宝公钥解密。
      2. 加签和验签
        1. sign生成规则:
          1. 发送给支付宝的所有参数、剔除sign、sign_type
          2. 按照参数字母顺序排序,且格式为key=value,参数之间使用&连接
          3. 使用对应的sign_type转换,如MD5
        2. 用户发送给支付宝的消息需要加签,即按照规则生成sign然后以参数sign传递过去,因为支付宝需要校验请求的正确性
        3. 支付宝回调的通知请求需要验签,因为用户也需要验证支付宝请求的正确性
    3. 工具
      1. 沙箱工具及使用 https://opendocs.alipay.com/common/02kkv7
      2. 支付应用文档可参考请求和响应参数 https://opendocs.alipay.com/open/02e7gq?scene=20
      3. 支付宝开放平台
      4. 异步通知URL,需要能被外网访问的网络,可以使用免费内网穿透工具生成域名ngrok 官网甚至有使用介绍,方便快捷
    4. 代码(手机网页支付,手机上提前下载好沙箱版支付宝)
        1. package main
        2. import (
        3. "context"
        4. "errors"
        5. "fmt"
        6. "github.com/go-pay/gopay"
        7. "github.com/go-pay/gopay/alipay"
        8. "github.com/go-pay/gopay/pkg/xlog"
        9. "github.com/kataras/iris/v12"
        10. "net/url"
        11. )
        12. //应用私钥
        13. var privateKey = ``
        14. func main() {
        15. // 1初始化支付宝客户端
        16. client, err := alipay.NewClient("appid", privateKey, false)
        17. if err != nil {
        18. xlog.Error(err)
        19. return
        20. }
        21. // 打开Debug开关,输出日志,默认关闭
        22. //client.DebugSwitch = gopay.DebugOn
        23. // 设置支付宝请求 公共参数
        24. client.SetLocation(alipay.LocationShanghai). // 设置时区,不设置或出错均为默认服务器时间
        25. SetCharset(alipay.UTF8). // 设置字符编码,不设置默认 utf-8
        26. SetSignType(alipay.RSA2). // 设置签名类型,不设置默认 RSA2
        27. SetReturnUrl("https://127.0.0.1:80/return"). //跳转页面
        28. SetNotifyUrl("https://本地地址80端口映射的域名/notify") // 异步通知URL 可被外网访问 post请求//.SetAppAuthToken() // 设置第三方应用授权
        29. // 自动同步验签(只支持证书模式)
        30. // 传入 alipayCertPublicKey_RSA2.crt 内容
        31. // client.AutoVerifySign([]byte(`-----BEGIN CERTIFICATE-----
        32. //-----END CERTIFICATE-----
        33. //`))
        34. // 公钥证书模式,需要传入证书,证书路径
        35. err = client.SetCertSnByPath("appCertPublicKey.crt", "alipayRootCert.crt", "alipayCertPublicKey_RSA2.crt")
        36. if err != nil {
        37. xlog.Error(err)
        38. return
        39. }
        40. // 2web服务器
        41. app := iris.New()
        42. app.Get("/pay", func(ctx iris.Context) { //支付
        43. Pay(context.Background(), client)
        44. })
        45. app.Get("/return", func(ctx iris.Context) { //返回页
        46. ReturnUrl(ctx)
        47. })
        48. app.Post("/notify", func(ctx iris.Context) { //通知页
        49. err = NotifyUrl(ctx)
        50. if err != nil {
        51. fmt.Println("通知页", err)
        52. }
        53. })
        54. err = app.Run(iris.Addr(":80"))
        55. if err != nil {
        56. fmt.Println(err)
        57. return
        58. }
        59. }
        60. // Pay 手机网站支付
        61. func Pay(ctx context.Context, client *alipay.Client) {
        62. //请求参数
        63. bm := make(gopay.BodyMap)
        64. bm.Set("subject", "手机网站支付")
        65. bm.Set("out_trade_no", "LP20220628") //一个订单号只能支付一次
        66. bm.Set("total_amount", "0.01") //1分钱
        67. fmt.Println("body:", bm)
        68. //发送请求
        69. payUrl, err := client.TradeWapPay(ctx, bm) //内部已经处理了签名
        70. if err != nil {
        71. xlog.Error(err)
        72. return
        73. }
        74. //支付界面链接,直接粘贴到手机浏览器里即可支付
        75. fmt.Println(payUrl)
        76. }
        77. // ReturnUrl 返回页 同步get,可在本机上测试
        78. func ReturnUrl(ctx iris.Context) {
        79. ctx.WriteString("ReturnUrl success")
        80. }
        81. // NotifyUrl 通知页 异步post,必须外网可访问,必须返回success否则会一直通知
        82. func NotifyUrl(ctx iris.Context) error {
        83. body, err := ctx.GetBody()
        84. if err != nil {
        85. fmt.Errorf("%v", err)
        86. return err
        87. }
        88. fmt.Println("body", string(body))
        89. values, err := url.ParseQuery(string(body))
        90. if err != nil {
        91. fmt.Errorf("%v", err)
        92. return err
        93. }
        94. datas, err := alipay.ParseNotifyByURLValues(values) //证书异步验签
        95. if err != nil {
        96. fmt.Errorf("%v", err)
        97. return err
        98. }
        99. //验签
        100. ok, err := alipay.VerifySignWithCert("alipayCertPublicKey_RSA2.crt", datas)
        101. if ok == false || err != nil {
        102. fmt.Errorf("%v", err)
        103. return errors.New("校验失败")
        104. }
        105. fmt.Println(datas)
        106. tradeStatus := datas.Get("trade_status")
        107. fmt.Printf(tradeStatus)
        108. //todo 处理业务逻辑
        109. //交易状态
        110. if tradeStatus == "TRADE_SUCCESS" {
        111. fmt.Println("交易成功")
        112. } else {
        113. fmt.Errorf("交易异常")
        114. }
        115. //返回success
        116. ctx.WriteString("success")
        117. return nil
        118. }

  • 相关阅读:
    2022年十一届认证杯(小美赛)C题思路新鲜出炉
    Python独具特色的语法规范点梳理
    docker基础01
    Sharding-JDBC(五)- Sharding-JDBC读写分离
    Alibaba Code代码索引技术实践:为Code Review提供本地IDE的阅读体验
    用HTML+CSS做一个学生抗疫感动专题网页设计作业网页
    虹科分享 | 终端安全防护 | 网络安全术语列表(上篇)
    提高测试覆盖率的四大步骤
    进程间的通信方式
    什么是泛型编程和模板技术?C语言中如何实现泛型编程?
  • 原文地址:https://blog.csdn.net/qq_37575994/article/details/125513319