xy_sh-20260723184208/xy_sh/internal/service/service.go

177 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"encoding/json"
"log"
"xy_sh/internal/biz"
"xy_sh/internal/config"
"xy_sh/internal/entities"
"xy_sh/pkg/crypto"
"github.com/gofiber/fiber/v2"
)
// RegisterRoutes 注册所有路由
func RegisterRoutes(app *fiber.App, cfg *config.Config) {
b := biz.NewBiz()
// 接口1卡券/直充权益下单
app.Post("/api/order/create", handleWithDecrypt(cfg, b, func(reqBytes []byte) (interface{}, error) {
var bizReq entities.OrderCreateBizReq
if err := json.Unmarshal(reqBytes, &bizReq); err != nil {
return nil, err
}
return b.CreateOrder(&bizReq)
}))
// 接口2卡券/直充/微信立减金订单查询
app.Post("/api/order/query", handleWithDecrypt(cfg, b, func(reqBytes []byte) (interface{}, error) {
var bizReq entities.OrderQueryBizReq
if err := json.Unmarshal(reqBytes, &bizReq); err != nil {
return nil, err
}
return b.QueryOrder(&bizReq)
}))
// 接口3微信立减金订单充值
app.Post("/api/order/recharge", handleWithDecrypt(cfg, b, func(reqBytes []byte) (interface{}, error) {
var bizReq entities.WechatRechargeBizReq
if err := json.Unmarshal(reqBytes, &bizReq); err != nil {
return nil, err
}
return b.WechatRecharge(&bizReq)
}))
// 接口4卡券/直充/微信立减金充值结果通知接口(接收供应商回调)
app.Post("/api/callback/notify", handleCallback(cfg, b))
}
// handleWithDecrypt 通用处理:验证签名 -> 解密 -> 执行业务 -> 加密响应
func handleWithDecrypt(cfg *config.Config, b biz.Biz, handler func([]byte) (interface{}, error)) fiber.Handler {
return func(c *fiber.Ctx) error {
// 1. 验证签名
timestamp := c.Get("timestamp")
sign := c.Get("sign")
if timestamp == "" || sign == "" {
return c.JSON(entities.ApiResponse{
Code: -1,
Msg: "缺少timestamp或sign",
})
}
// 2. 获取加密数据
var reqBody struct {
EncryptedData string `json:"encryptedData"`
}
if err := c.BodyParser(&reqBody); err != nil {
return c.JSON(entities.ApiResponse{
Code: -1,
Msg: "请求体解析失败",
})
}
// 3. 验证SM3签名sign = SM3(salt + timestamp + encryptedData)
expectedSign := crypto.SM3WithSalt(cfg.SM3Salt, timestamp+reqBody.EncryptedData)
if expectedSign != sign {
log.Printf("签名验证失败: expected=%s, got=%s", expectedSign, sign)
return c.JSON(entities.ApiResponse{
Code: -1,
Msg: "签名验证失败",
})
}
// 4. SM4解密业务数据
bizData, err := crypto.SM4ECBDecrypt(reqBody.EncryptedData, cfg.SM4Key)
if err != nil {
log.Printf("SM4解密失败: %v", err)
return c.JSON(entities.ApiResponse{
Code: -1,
Msg: "数据解密失败",
})
}
// 5. 执行业务逻辑
result, err := handler(bizData)
if err != nil {
log.Printf("业务处理失败: %v", err)
return c.JSON(entities.ApiResponse{
Code: -1,
Msg: err.Error(),
})
}
// 6. 加密响应数据
respBytes, err := json.Marshal(result)
if err != nil {
return c.JSON(entities.ApiResponse{
Code: -1,
Msg: "响应序列化失败",
})
}
encryptedResp, err := crypto.SM4ECBEncrypt(respBytes, cfg.SM4Key)
if err != nil {
return c.JSON(entities.ApiResponse{
Code: -1,
Msg: "响应加密失败",
})
}
return c.JSON(entities.ApiResponse{
Code: 0,
Msg: "请求成功",
Data: encryptedResp,
})
}
}
// handleCallback 处理供应商回调通知
func handleCallback(cfg *config.Config, b biz.Biz) fiber.Handler {
return func(c *fiber.Ctx) error {
// 1. 验证签名
timestamp := c.Get("timestamp")
sign := c.Get("sign")
if timestamp == "" || sign == "" {
return c.Status(400).SendString("missing auth headers")
}
// 2. 获取加密数据
var reqBody struct {
EncryptedData string `json:"encryptedData"`
}
if err := c.BodyParser(&reqBody); err != nil {
return c.Status(400).SendString("invalid body")
}
// 3. 验证SM3签名
expectedSign := crypto.SM3WithSalt(cfg.SM3Salt, timestamp+reqBody.EncryptedData)
if expectedSign != sign {
log.Printf("回调签名验证失败: expected=%s, got=%s", expectedSign, sign)
return c.Status(400).SendString("sign verification failed")
}
// 4. SM4解密业务数据
bizData, err := crypto.SM4ECBDecrypt(reqBody.EncryptedData, cfg.SM4Key)
if err != nil {
log.Printf("回调数据SM4解密失败: %v", err)
return c.Status(400).SendString("decrypt failed")
}
// 5. 解析回调业务参数
var callbackReq entities.CallbackNotifyBizReq
if err := json.Unmarshal(bizData, &callbackReq); err != nil {
log.Printf("回调数据解析失败: %v", err)
return c.Status(400).SendString("parse failed")
}
// 6. 处理回调业务
if err := b.ProcessCallback(&callbackReq); err != nil {
log.Printf("回调处理失败: %v", err)
return c.Status(500).SendString("process failed")
}
// 7. 返回成功必须返回200且内容为ok
return c.Status(200).SendString("ok")
}
}