diff --git a/backend/app/http/orders.go b/backend/app/http/orders.go deleted file mode 100644 index d02cfda..0000000 --- a/backend/app/http/orders.go +++ /dev/null @@ -1 +0,0 @@ -package http diff --git a/backend/app/http/pays.go b/backend/app/http/pays.go new file mode 100644 index 0000000..0a5db8f --- /dev/null +++ b/backend/app/http/pays.go @@ -0,0 +1,50 @@ +package http + +import ( + "fmt" + "net/http" + + "quyun/providers/wepay" + + "github.com/go-pay/gopay" + "github.com/go-pay/gopay/wechat/v3" + "github.com/go-pay/util/js" + "github.com/gofiber/fiber/v3" +) + +type pays struct { + wepay *wepay.Client +} + +// Callback +// @Router /pay/callback [get] +func (ctl *pays) Callback(ctx fiber.Ctx) error { + body := ctx.Body() + si := &wechat.SignInfo{ + HeaderTimestamp: ctx.Get(wechat.HeaderTimestamp), + HeaderNonce: ctx.Get(wechat.HeaderNonce), + HeaderSignature: ctx.Get(wechat.HeaderSignature), + HeaderSerial: ctx.Get(wechat.HeaderSerial), + SignBody: string(body), + } + notifyReq := &wechat.V3NotifyReq{SignInfo: si} + if err := js.UnmarshalBytes(body, notifyReq); err != nil { + return ctx.Status(http.StatusBadRequest).JSON(fiber.Map{"error": fmt.Sprintf("json unmarshal error:%v", err)}) + } + + // 获取微信平台证书 + certMap := ctl.wepay.WxPublicKeyMap() + + // 验证异步通知的签名 + err := notifyReq.VerifySignByPKMap(certMap) + if err != nil { + return ctx.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "Invalid signature"}) + } + + // TODO: add process order job + + return ctx.Status(http.StatusOK).JSON(&wechat.V3NotifyRsp{ + Code: gopay.SUCCESS, + Message: "成功", + }) +} diff --git a/backend/app/http/posts.go b/backend/app/http/posts.go index 17077e7..e06e1fe 100644 --- a/backend/app/http/posts.go +++ b/backend/app/http/posts.go @@ -8,6 +8,7 @@ import ( "quyun/database/schemas/public/model" "quyun/providers/wepay" + "github.com/go-pay/gopay/wechat/v3" "github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3/log" "github.com/pkg/errors" @@ -50,7 +51,7 @@ func (ctl *posts) Mine(ctx fiber.Ctx, pagination *requests.Pagination, query *Li // Buy // @Router /buy/:id [get] // @Bind id path -func (ctl *posts) Buy(ctx fiber.Ctx, id int64) (*wepay.PrepayData, error) { +func (ctl *posts) Buy(ctx fiber.Ctx, id int64) (*wechat.JSAPIPayParams, error) { var userId int64 = 1 user, err := models.Users.GetByID(ctx.Context(), userId) @@ -80,5 +81,6 @@ func (ctl *posts) Buy(ctx fiber.Ctx, id int64) (*wepay.PrepayData, error) { log.Errorf("wepay.V3TransactionJsapi err: %v", err) return nil, errors.Wrap(err, "微信支付失败") } - return prePayResp, nil + + return prePayResp.PaySignOfJSAPI() } diff --git a/backend/app/http/provider.gen.go b/backend/app/http/provider.gen.go index fd34a14..3ac7a60 100755 --- a/backend/app/http/provider.gen.go +++ b/backend/app/http/provider.gen.go @@ -1,6 +1,8 @@ package http import ( + "quyun/providers/wepay" + "go.ipao.vip/atom" "go.ipao.vip/atom/container" "go.ipao.vip/atom/contracts" @@ -8,17 +10,23 @@ import ( ) func Provide(opts ...opt.Option) error { - if err := container.Container.Provide(func() (*posts, error) { - obj := &posts{} + if err := container.Container.Provide(func( + wepay *wepay.Client, + ) (*posts, error) { + obj := &posts{ + wepay: wepay, + } return obj, nil }); err != nil { return err } if err := container.Container.Provide(func( + pays *pays, posts *posts, ) (contracts.HttpRoute, error) { obj := &Routes{ + pays: pays, posts: posts, } if err := obj.Prepare(); err != nil { diff --git a/backend/app/http/routes.gen.go b/backend/app/http/routes.gen.go index 0cc7995..19089fa 100644 --- a/backend/app/http/routes.gen.go +++ b/backend/app/http/routes.gen.go @@ -14,6 +14,7 @@ import ( // @provider contracts.HttpRoute atom.GroupRoutes type Routes struct { log *log.Entry `inject:"false"` + pays *pays posts *posts } @@ -27,8 +28,13 @@ func (r *Routes) Name() string { } func (r *Routes) Register(router fiber.Router) { + // 注册路由组: pays + router.Get("/pay/callback", Func0( + r.pays.Callback, + )) + // 注册路由组: posts - router.Get("/", DataFunc2( + router.Get("/posts", DataFunc2( r.posts.List, Query[requests.Pagination]("pagination"), Query[ListQuery]("query"), @@ -45,4 +51,9 @@ func (r *Routes) Register(router fiber.Router) { Query[ListQuery]("query"), )) + router.Get("/buy/:id", DataFunc1( + r.posts.Buy, + PathParam[int64]("id"), + )) + } diff --git a/backend/providers/wepay/pay.go b/backend/providers/wepay/pay.go index cef2f0c..8e18479 100644 --- a/backend/providers/wepay/pay.go +++ b/backend/providers/wepay/pay.go @@ -2,6 +2,7 @@ package wepay import ( "context" + "crypto/rsa" "encoding/json" "errors" "time" @@ -55,11 +56,23 @@ func (c *Client) GetClient() *wechat.ClientV3 { return c.payClient } +// WxPublicKeyMap +func (c *Client) WxPublicKeyMap() map[string]*rsa.PublicKey { + return c.payClient.WxPublicKeyMap() +} + type PrepayData struct { + client *Client + AppID string `json:"app_id"` PrepayID string `json:"prepay_id"` } +// PaySignOfJSAPI +func (pay *PrepayData) PaySignOfJSAPI() (*wechat.JSAPIPayParams, error) { + return pay.client.payClient.PaySignOfJSAPI(pay.AppID, pay.PrepayID) +} + func (c *Client) V3TransactionJsapi(ctx context.Context, f func(*BodyMap)) (*PrepayData, error) { bm := NewBodyMap(c.config) f(bm) @@ -76,6 +89,8 @@ func (c *Client) V3TransactionJsapi(ctx context.Context, f func(*BodyMap)) (*Pre } return &PrepayData{ + client: c, + AppID: c.config.AppID, PrepayID: resp.Response.PrepayId, }, nil diff --git a/backend/providers/wepay/pay_test.go b/backend/providers/wepay/pay_test.go index f9e8566..2d470b0 100644 --- a/backend/providers/wepay/pay_test.go +++ b/backend/providers/wepay/pay_test.go @@ -45,8 +45,11 @@ func (s *WePayTestSuite) Test_PrePay() { }) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) - s.T().Logf("prepay response: %+v", resp) + + sign, err := resp.PaySignOfJSAPI() + So(err, ShouldBeNil) + s.T().Logf("Sign: %+v", sign) }) }) }