From b1a1a4cd50e84749b77c12bb7452176fb5fb98b1 Mon Sep 17 00:00:00 2001 From: Rzy <465386466@qq.com> Date: Mon, 5 Aug 2024 14:05:46 +0800 Subject: [PATCH] =?UTF-8?q?api=E8=A1=A8=E5=8D=95=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/constants/errorcode/error_code.go | 52 ++++++++++++++------------- app/http/controllers/base.go | 28 +++++++++++++++ app/http/controllers/front/api.go | 10 ++++++ app/http/entities/front/pay.go | 6 ++-- app/http/middlewares/base.go | 33 +++++++++++++---- app/http/requestmapping/front.go | 6 ++++ app/http/routes/route.go | 12 ++++--- app/services/api_request_valid.go | 15 ++++++++ app/services/apicrypt/rsa.go | 17 +++++---- app/services/apicrypt/types.go | 2 ++ app/utils/encrypt/rsa/rsa_test.go | 7 ++-- 11 files changed, 139 insertions(+), 49 deletions(-) create mode 100644 app/http/controllers/front/api.go diff --git a/app/constants/errorcode/error_code.go b/app/constants/errorcode/error_code.go index 717a52f..43a5715 100644 --- a/app/constants/errorcode/error_code.go +++ b/app/constants/errorcode/error_code.go @@ -30,21 +30,22 @@ const ( // app - AppNotFound = 1200 - AppDisabled = 1201 - AppIpNotAllow = 1202 - AppRsaDecryptKeyNotFound = 1203 - AppRsaDecryptFail = 1210 - AppRsaEncryptKeyNotFound = 1211 - AppRsaEncryptFail = 1212 - AppSM2DecryptKeyNotFound = 1220 - AppSM2DecryptFail = 1221 - AppSM2EncryptKeyNotFound = 1222 - AppSM2EncryptFail = 1223 - AppSM4DecryptKeyNotFound = 1230 - AppSM4DecryptFail = 1231 - AppSM4EncryptKeyNotFound = 1232 - AppSM4EncryptFail = 1233 + AppNotFound = 1200 + AppDisabled = 1201 + AppIpNotAllow = 1202 + AppRsaDecryptKeyNotFound = 1203 + AppDecryptDataDiscrepancy = 1204 + AppRsaDecryptFail = 1210 + AppRsaEncryptKeyNotFound = 1211 + AppRsaEncryptFail = 1212 + AppSM2DecryptKeyNotFound = 1220 + AppSM2DecryptFail = 1221 + AppSM2EncryptKeyNotFound = 1222 + AppSM2EncryptFail = 1223 + AppSM4DecryptKeyNotFound = 1230 + AppSM4DecryptFail = 1231 + AppSM4EncryptKeyNotFound = 1232 + AppSM4EncryptFail = 1233 //渠道 PayChannelNotFound = 1300 @@ -60,16 +61,17 @@ var MsgEN = map[int]string{ } var MsgZH = map[int]string{ - Success: "请求成功", - ParamError: "参数错误", - NotFound: "数据不存在", - NotAuth: "未经授权", - NotLogin: "未登录", - RequestTimeOut: "请求超时", - MerchantNotFound: "商户不存在", - AppNotFound: "app_id未找到", - AppDisabled: "app通道关闭", - AppIpNotAllow: "ip不在白名单内", + Success: "请求成功", + ParamError: "参数错误", + NotFound: "数据不存在", + NotAuth: "未经授权", + NotLogin: "未登录", + RequestTimeOut: "请求超时", + MerchantNotFound: "商户不存在", + AppNotFound: "app_id未找到", + AppDisabled: "app通道关闭", + AppIpNotAllow: "ip不在白名单内", + AppDecryptDataDiscrepancy: "解密数据不一致", AppRsaDecryptKeyNotFound: "密匙缺失,无法进行Rsa解密", AppRsaDecryptFail: "Rsa解密失败", diff --git a/app/http/controllers/base.go b/app/http/controllers/base.go index bd68940..92fd2d6 100644 --- a/app/http/controllers/base.go +++ b/app/http/controllers/base.go @@ -149,6 +149,34 @@ func GenRequest(c *gin.Context, request interface{}) (msgs []string, err error) return } +func ValidApiData(dataByte []byte, validStruct interface{}) (msgs []string, err error) { + validate := validator.New() + err = json.Unmarshal(dataByte, validStruct) + if err != nil { + err = errors.New(errorcode.GetMsg(errorcode.ParamError, "")) + } + zh_ch := zh.New() + uni := ut.New(zh_ch) + trans, _ := uni.GetTranslator("zh") + //注册一个函数,获取struct tag里自定义的label作为字段名 + validate.RegisterTagNameFunc(func(fld reflect.StructField) string { + name := fld.Tag.Get("label") + return name + }) + //验证器注册翻译器 + _ = zh_translations.RegisterDefaultTranslations(validate, trans) + errValidate := validate.Struct(validStruct) + if errValidate != nil { + // 如果有错误,打印出来 + for _, v := range errValidate.(validator.ValidationErrors) { + msgs = append(msgs, v.Translate(trans)) + } + err = errors.New(errorcode.GetMsg(errorcode.ParamError, "")) + return + } + return +} + // 重复读取body func ReadBody(c *gin.Context) (body []byte, err error) { body, err = ioutil.ReadAll(c.Request.Body) diff --git a/app/http/controllers/front/api.go b/app/http/controllers/front/api.go new file mode 100644 index 0000000..15942d1 --- /dev/null +++ b/app/http/controllers/front/api.go @@ -0,0 +1,10 @@ +package front + +import ( + "fmt" + "github.com/gin-gonic/gin" +) + +func WebPay(c *gin.Context) { + fmt.Println("312312312321") +} diff --git a/app/http/entities/front/pay.go b/app/http/entities/front/pay.go index 7efc930..67daf3b 100644 --- a/app/http/entities/front/pay.go +++ b/app/http/entities/front/pay.go @@ -1,6 +1,6 @@ package front -type PayCommonBody struct { +type ApiCommonBody struct { AppId int64 `json:"app_id" validate:"required"` Timestamp int64 `json:"timestamp" validate:"required"` } @@ -12,7 +12,7 @@ type RequestBody struct { } type PayWeb struct { - PayCommonBody - PayChannel int64 `json:"private_key_path"` + ApiCommonBody + PayChannel int64 `json:"private_key_path" validate:"required" label:"支付渠道"` Delay int64 `json:"delay"` //延时时间 } diff --git a/app/http/middlewares/base.go b/app/http/middlewares/base.go index 5958e34..c31ed96 100644 --- a/app/http/middlewares/base.go +++ b/app/http/middlewares/base.go @@ -8,6 +8,7 @@ import ( "PaymentCenter/app/http/entities/front" "PaymentCenter/app/http/requestmapping" "PaymentCenter/app/services" + "PaymentCenter/app/services/apicrypt" "PaymentCenter/app/utils" "PaymentCenter/config" "github.com/gin-gonic/gin" @@ -107,7 +108,7 @@ func ValidateRequest() gin.HandlerFunc { if strings.Index(path, "admin") >= 0 { handler = requestmapping.BackendRequestMap[path] } else { - handler = requestmapping.FrontRequestMap[path] + handler = requestmapping.FrontRequest() } if handler == nil { utils.Log(c, "path", path) @@ -129,11 +130,14 @@ func ValidateRequest() gin.HandlerFunc { func ValidatePayRequest() gin.HandlerFunc { return func(c *gin.Context) { - commonData, err := utils.SonicApiDataToStruct(controllers.GetRequest(c), &front.RequestBody{}) + var path = c.FullPath() + var handler func() interface{} + requestData, err := utils.SonicApiDataToStruct(controllers.GetRequest(c), &front.RequestBody{}) if err != nil { controllers.ErrWithCode(c, errorcode.ParamError) + return } - commonDataStruct := commonData.(*front.RequestBody) + requestDataStruct := requestData.(*front.RequestBody) //判断时间 //now := time.Now().UnixNano() / 1000000 //if comStruct.Timestamp > now || (config.GetConf().TimeOut != 0 && (now-comStruct.Timestamp) > config.GetConf().TimeOut) { @@ -141,7 +145,7 @@ func ValidatePayRequest() gin.HandlerFunc { // return //} //获取app信息 - app, errCode := services.AppFindOne(entities.IdRequest{Id: commonDataStruct.AppId}) + app, errCode := services.AppFindOne(entities.IdRequest{Id: requestDataStruct.AppId}) if errCode != errorcode.Success { controllers.ErrWithCode(c, errCode) return @@ -162,12 +166,27 @@ func ValidatePayRequest() gin.HandlerFunc { if cryptFunc == nil { controllers.ErrWithCode(c, appCheck.GetCode()) } - data, errCode := cryptFunc(app).Decrypt(commonDataStruct.Data) - if errCode != errorcode.Success { + dataByte, errCode := cryptFunc(app).Decrypt(requestDataStruct.Data) + if errCode != apicrypt.CryptNotError { controllers.ErrWithCode(c, errCode) return } - c.Set("request", data) + //检查解密后的数据是否与请求一致 + reCheck := appCheck.ReCheckAfterDecrypt(dataByte, requestDataStruct) + if !reCheck { + controllers.ErrWithCode(c, appCheck.GetCode()) + return + } + //表单验证 + handler = requestmapping.FrontRequestMap[path] + v := handler() + msg, err := controllers.ValidApiData(dataByte, v) + if err != nil { + utils.Log(c, "参数错误", "path=", path, "err=", err.Error(), "msg=", msg) + controllers.Error(c, errorcode.ParamError, msg...) + c.Abort() + } + c.Set("request", dataByte) c.Next() } } diff --git a/app/http/requestmapping/front.go b/app/http/requestmapping/front.go index 5660770..9aa8e13 100644 --- a/app/http/requestmapping/front.go +++ b/app/http/requestmapping/front.go @@ -8,3 +8,9 @@ import ( var FrontRequestMap = map[string]func() interface{}{ common.FRONT_V1 + "/pay/web": func() interface{} { return new(front.PayWeb) }, } + +func FrontRequest() func() interface{} { + return func() interface{} { + return new(front.RequestBody) + } +} diff --git a/app/http/routes/route.go b/app/http/routes/route.go index e0dc7ff..c1df4fa 100644 --- a/app/http/routes/route.go +++ b/app/http/routes/route.go @@ -4,8 +4,8 @@ package routes * 配置路由 */ import ( + "PaymentCenter/app/constants/common" "PaymentCenter/app/http/controllers" - "PaymentCenter/app/http/controllers/backend" "PaymentCenter/app/http/controllers/front" "PaymentCenter/app/http/middlewares" "PaymentCenter/app/http/trace" @@ -47,7 +47,7 @@ func RegisterRoute(router *gin.Engine) { //router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - v1 := router.Group("/v1") + v1 := router.Group(common.FRONT_V1) { //回调处理 notify := v1.Group("/notify") @@ -55,9 +55,13 @@ func RegisterRoute(router *gin.Engine) { notify.POST("/wx/:payChannelId", front.WxCallback) notify.POST("/ali/:payChannelId", front.AliCallback) } + + pay := v1.Group("/pay", middlewares.ValidateRequest(), middlewares.ValidatePayRequest()) + { + pay.POST("/web", front.WebPay) + } } router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - pay := v1.Group("pay", middlewares.ValidatePayRequest()) - pay.POST("web", backend.MerchantList) // 商户列表 + } diff --git a/app/services/api_request_valid.go b/app/services/api_request_valid.go index 9174112..0c6ed47 100644 --- a/app/services/api_request_valid.go +++ b/app/services/api_request_valid.go @@ -3,9 +3,11 @@ package services import ( "PaymentCenter/app/constants/errorcode" "PaymentCenter/app/constants/pojo" + "PaymentCenter/app/http/entities/front" "PaymentCenter/app/models/appmodel" "PaymentCenter/app/services/apicrypt" "PaymentCenter/app/utils" + "github.com/bytedance/sonic" "strings" ) @@ -59,3 +61,16 @@ func (a *AppCheck) Crypt() (cryptFunc func(app *appmodel.App) apicrypt.ApiCrypt) } return cryptFunc } + +func (a *AppCheck) ReCheckAfterDecrypt(data []byte, requestData *front.RequestBody) bool { + var requestCommonData front.ApiCommonBody + if err := sonic.Unmarshal(data, &requestCommonData); err != nil { + a.Code = errorcode.ParamError + return false + } + if requestCommonData.AppId != requestData.AppId || requestCommonData.Timestamp != requestData.Timestamp { + a.Code = errorcode.AppDecryptDataDiscrepancy + return false + } + return true +} diff --git a/app/services/apicrypt/rsa.go b/app/services/apicrypt/rsa.go index 231fd33..69012ac 100644 --- a/app/services/apicrypt/rsa.go +++ b/app/services/apicrypt/rsa.go @@ -13,11 +13,13 @@ func NewRsa(app *appmodel.App) ApiCrypt { } func (r *Rsa) Encrypt(decryptData string) (encryptData []byte, errCode int) { - if r.App.MerchantPublicKey == "" { + if r.App.PublicKey == "" { return nil, errorcode.AppRsaEncryptKeyNotFound } - // - encryptData, err := rsa.Encrypt(r.App.MerchantPublicKey, []byte(decryptData)) + publicKeyPEM := `-----BEGIN PUBLIC KEY----- +` + r.App.PublicKey + ` +-----END PUBLIC KEY-----` + encryptData, err := rsa.Encrypt(publicKeyPEM, []byte(decryptData)) if err != nil { return nil, errorcode.AppRsaEncryptFail } @@ -26,12 +28,15 @@ func (r *Rsa) Encrypt(decryptData string) (encryptData []byte, errCode int) { } func (r *Rsa) Decrypt(encryptData string) (decryptData []byte, errCode int) { + if r.App.PrivateKey == "" { return nil, errorcode.AppRsaDecryptKeyNotFound } - - decryptData, err := rsa.Decrypt(r.App.PrivateKey, encryptData) - if err != nil { + privateKeyPEM := `-----BEGIN RSA PRIVATE KEY----- +` + r.App.PrivateKey + ` +-----END RSA PRIVATE KEY-----` + decryptData, err := rsa.Decrypt(privateKeyPEM, encryptData) + if err != nil || decryptData == nil { return nil, errorcode.AppRsaDecryptFail } return diff --git a/app/services/apicrypt/types.go b/app/services/apicrypt/types.go index e672fd2..533de39 100644 --- a/app/services/apicrypt/types.go +++ b/app/services/apicrypt/types.go @@ -29,3 +29,5 @@ var ApiCryptMap = map[int32]func(app *appmodel.App) ApiCrypt{ pojo.SM2: NewSm2, pojo.SM4: NewSm4, } + +const CryptNotError = 0 diff --git a/app/utils/encrypt/rsa/rsa_test.go b/app/utils/encrypt/rsa/rsa_test.go index 5425c75..628568e 100644 --- a/app/utils/encrypt/rsa/rsa_test.go +++ b/app/utils/encrypt/rsa/rsa_test.go @@ -4,7 +4,6 @@ import ( "encoding/base64" "fmt" "testing" - "time" ) const ( @@ -14,8 +13,8 @@ const ( ) func TestRsaEncrypt(t *testing.T) { - fmt.Println(time.Now().UnixNano() / (1000000)) - //fmt.Printf("%s\n", encrypt()) + + fmt.Printf("%s\n", encrypt()) } func TestRsaDecrypt(t *testing.T) { @@ -28,7 +27,7 @@ func TestRsaDecrypt(t *testing.T) { } func encrypt() string { - data := "{\"name\":\"张三\",\"sex\":1,\"is_human\":true}" + data := "{\"app_id\":5476377146882523138,\"name\":\"张三\",\"sex\":1,\"is_human\":true,\"timestamp\":53612533412643}" dataJson := []byte(data) pub := `-----BEGIN PUBLIC KEY----- ` + PUB + `