实现Apple应用内购支付功能,包括: 1. 新增AppleIAP和ApplePay支付平台枚举 2. 添加IAP验证接口/v1/public/iap/verify处理初购验证 3. 实现Apple服务器通知处理逻辑/v1/iap/notifications 4. 新增JWS验签和JWKS公钥缓存功能 5. 复用现有订单系统处理IAP支付订单 相关文档已更新,包含接入方案和实现细节
This commit is contained in:
@@ -8,10 +8,15 @@ import (
|
||||
)
|
||||
|
||||
func RegisterNotifyHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
||||
group := router.Group("/v1/notify/")
|
||||
group.Use(middleware.NotifyMiddleware(serverCtx))
|
||||
{
|
||||
group.Any("/:platform/:token", notify.PaymentNotifyHandler(serverCtx))
|
||||
}
|
||||
group := router.Group("/v1/notify/")
|
||||
group.Use(middleware.NotifyMiddleware(serverCtx))
|
||||
{
|
||||
group.Any(":platform/:token", notify.PaymentNotifyHandler(serverCtx))
|
||||
}
|
||||
|
||||
iap := router.Group("/v1/iap")
|
||||
{
|
||||
iap.POST("/notifications", notify.AppleIAPNotifyHandler(serverCtx))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/perfect-panel/server/internal/logic/notify"
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/pkg/result"
|
||||
)
|
||||
|
||||
// AppleIAPNotifyHandler 处理 Apple Server Notifications v2
|
||||
// 参数: 原始 HTTP 请求体
|
||||
// 返回: 处理结果(空体 200)
|
||||
func AppleIAPNotifyHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) {
|
||||
return func(c *gin.Context) {
|
||||
l := notify.NewAppleIAPNotifyLogic(c.Request.Context(), svcCtx)
|
||||
err := l.Handle(c.Request)
|
||||
result.HttpResult(c, gin.H{"success": err == nil}, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func PaymentNotifyHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, "%s", "success")
|
||||
case payment.Stripe:
|
||||
case payment.Stripe, payment.ApplePay:
|
||||
l := notify.NewStripeNotifyLogic(c.Request.Context(), svcCtx)
|
||||
if err := l.StripeNotify(c.Request, c.Writer); err != nil {
|
||||
result.HttpResult(c, nil, err)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package iap
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/perfect-panel/server/internal/logic/public/iap"
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/internal/types"
|
||||
"github.com/perfect-panel/server/pkg/result"
|
||||
)
|
||||
|
||||
// VerifyHandler 处理 iOS IAP 初购验证并生成已支付订单
|
||||
// 参数: IAPVerifyRequest
|
||||
// 返回: IAPVerifyResponse
|
||||
func VerifyHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) {
|
||||
return func(c *gin.Context) {
|
||||
var req types.IAPVerifyRequest
|
||||
_ = c.ShouldBind(&req)
|
||||
validateErr := svcCtx.Validate(&req)
|
||||
if validateErr != nil {
|
||||
result.ParamErrorResult(c, validateErr)
|
||||
return
|
||||
}
|
||||
|
||||
l := iap.NewVerifyLogic(c.Request.Context(), svcCtx)
|
||||
resp, err := l.Verify(&req)
|
||||
result.HttpResult(c, resp, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ import (
|
||||
authOauth "github.com/perfect-panel/server/internal/handler/auth/oauth"
|
||||
common "github.com/perfect-panel/server/internal/handler/common"
|
||||
publicAnnouncement "github.com/perfect-panel/server/internal/handler/public/announcement"
|
||||
publicDocument "github.com/perfect-panel/server/internal/handler/public/document"
|
||||
publicDocument "github.com/perfect-panel/server/internal/handler/public/document"
|
||||
publicIAP "github.com/perfect-panel/server/internal/handler/public/iap"
|
||||
publicOrder "github.com/perfect-panel/server/internal/handler/public/order"
|
||||
publicPayment "github.com/perfect-panel/server/internal/handler/public/payment"
|
||||
publicPortal "github.com/perfect-panel/server/internal/handler/public/portal"
|
||||
@@ -671,7 +672,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
||||
publicAnnouncementGroupRouter.GET("/list", publicAnnouncement.QueryAnnouncementHandler(serverCtx))
|
||||
}
|
||||
|
||||
publicDocumentGroupRouter := router.Group("/v1/public/document")
|
||||
publicDocumentGroupRouter := router.Group("/v1/public/document")
|
||||
publicDocumentGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx))
|
||||
|
||||
{
|
||||
@@ -680,7 +681,14 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
||||
|
||||
// Get document list
|
||||
publicDocumentGroupRouter.GET("/list", publicDocument.QueryDocumentListHandler(serverCtx))
|
||||
}
|
||||
}
|
||||
|
||||
publicIAPGroupRouter := router.Group("/v1/public/iap")
|
||||
publicIAPGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx))
|
||||
|
||||
{
|
||||
publicIAPGroupRouter.POST("/verify", publicIAP.VerifyHandler(serverCtx))
|
||||
}
|
||||
|
||||
publicOrderGroupRouter := router.Group("/v1/public/order")
|
||||
publicOrderGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx))
|
||||
|
||||
Reference in New Issue
Block a user