From d5200d00c9e10a22e76adda3406403b9369d7bb2 Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Tue, 18 Mar 2025 22:07:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=96=B0=E4=B8=AA=E4=BA=BA?= =?UTF-8?q?=E5=92=8C=E4=BC=81=E4=B8=9A=E5=8F=B8=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/api.api | 8 +- .../internal/handler/FLXG/flxg0v4bhandler.go | 30 +++++ .../internal/handler/QYGL/qygl8271handler.go | 31 +++++ apps/api/internal/handler/routes.go | 12 +- apps/api/internal/logic/FLXG/flxg0v4blogic.go | 111 ++++++++++++++++++ apps/api/internal/logic/QYGL/qygl8271logic.go | 111 ++++++++++++++++++ apps/api/internal/types/types.go | 2 +- apps/api/internal/validator/error_messages.go | 1 + apps/api/internal/validator/structs.go | 10 ++ apps/api/internal/validator/validator.go | 70 ++++++++++- apps/api/internal/westmodel/fieldMapping.go | 10 ++ apps/gateway/internal/validator/validator.go | 1 + 12 files changed, 393 insertions(+), 4 deletions(-) create mode 100644 apps/api/internal/handler/FLXG/flxg0v4bhandler.go create mode 100644 apps/api/internal/handler/QYGL/qygl8271handler.go create mode 100644 apps/api/internal/logic/FLXG/flxg0v4blogic.go create mode 100644 apps/api/internal/logic/QYGL/qygl8271logic.go diff --git a/apps/api/api.api b/apps/api/api.api index d8d28c9..b254507 100644 --- a/apps/api/api.api +++ b/apps/api/api.api @@ -8,7 +8,7 @@ info ( ) type request { - data string `json:"data"` + Data string `json:"data"` } @server ( @@ -74,6 +74,9 @@ service api-api { @handler FLXG0V3B post /FLXG0V3B (request) returns (string) + + @handler FLXG0V4B + post /FLXG0V4B (request) returns (string) } @server ( @@ -88,6 +91,9 @@ service api-api { @handler QYGL8261 post /QYGL8261 (request) returns (string) + @handler QYGL8271 + post /QYGL8271 (request) returns (string) + @handler QYGL45BD post /QYGL45BD (request) returns (string) diff --git a/apps/api/internal/handler/FLXG/flxg0v4bhandler.go b/apps/api/internal/handler/FLXG/flxg0v4bhandler.go new file mode 100644 index 0000000..5f8009d --- /dev/null +++ b/apps/api/internal/handler/FLXG/flxg0v4bhandler.go @@ -0,0 +1,30 @@ +package FLXG + +import ( + "net/http" + "tianyuan-api/pkg/errs" + "tianyuan-api/pkg/response" + + "github.com/zeromicro/go-zero/rest/httpx" + "tianyuan-api/apps/api/internal/logic/FLXG" + "tianyuan-api/apps/api/internal/svc" + "tianyuan-api/apps/api/internal/types" +) + +func FLXG0V4BHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.Request + if err := httpx.Parse(r, &req); err != nil { + response.Fail(r.Context(), w, errs.ErrParamValidation, nil) + return + } + + l := FLXG.NewFLXG0V4BLogic(r.Context(), svcCtx) + resp, err := l.FLXG0V4B(&req) + if err != nil { + response.Fail(r.Context(), w, err, resp) + } else { + response.Success(r.Context(), w, resp) + } + } +} diff --git a/apps/api/internal/handler/QYGL/qygl8271handler.go b/apps/api/internal/handler/QYGL/qygl8271handler.go new file mode 100644 index 0000000..e958193 --- /dev/null +++ b/apps/api/internal/handler/QYGL/qygl8271handler.go @@ -0,0 +1,31 @@ +package QYGL + +import ( + "net/http" + + "tianyuan-api/apps/api/internal/logic/QYGL" + "tianyuan-api/apps/api/internal/svc" + "tianyuan-api/apps/api/internal/types" + "tianyuan-api/pkg/errs" + "tianyuan-api/pkg/response" + + "github.com/zeromicro/go-zero/rest/httpx" +) + +func QYGL8271Handler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.Request + if err := httpx.Parse(r, &req); err != nil { + response.Fail(r.Context(), w, errs.ErrParamValidation, nil) + return + } + + l := QYGL.NewQYGL8271Logic(r.Context(), svcCtx) + resp, err := l.QYGL8271(&req) + if err != nil { + response.Fail(r.Context(), w, err, resp) + } else { + response.Success(r.Context(), w, resp) + } + } +} diff --git a/apps/api/internal/handler/routes.go b/apps/api/internal/handler/routes.go index 249fc8a..3ae422a 100644 --- a/apps/api/internal/handler/routes.go +++ b/apps/api/internal/handler/routes.go @@ -1,5 +1,5 @@ // Code generated by goctl. DO NOT EDIT. -// goctl 1.7.2 +// goctl 1.7.3 package handler @@ -26,6 +26,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/FLXG0V3B", Handler: FLXG.FLXG0V3BHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/FLXG0V4B", + Handler: FLXG.FLXG0V4BHandler(serverCtx), + }, { Method: http.MethodPost, Path: "/FLXG162A", @@ -173,6 +178,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/QYGL8261", Handler: QYGL.QYGL8261Handler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/QYGL8271", + Handler: QYGL.QYGL8271Handler(serverCtx), + }, { Method: http.MethodPost, Path: "/QYGLB4C0", diff --git a/apps/api/internal/logic/FLXG/flxg0v4blogic.go b/apps/api/internal/logic/FLXG/flxg0v4blogic.go new file mode 100644 index 0000000..0c84d5b --- /dev/null +++ b/apps/api/internal/logic/FLXG/flxg0v4blogic.go @@ -0,0 +1,111 @@ +package FLXG + +import ( + "context" + "encoding/hex" + "tianyuan-api/apps/api/internal/common" + "tianyuan-api/apps/api/internal/validator" + "tianyuan-api/apps/api/internal/westmodel" + "tianyuan-api/pkg/crypto" + "tianyuan-api/pkg/errs" + + "tianyuan-api/apps/api/internal/svc" + "tianyuan-api/apps/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type FLXG0V4BLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewFLXG0V4BLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FLXG0V4BLogic { + return &FLXG0V4BLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FLXG0V4BLogic) FLXG0V4B(req *types.Request) (resp string, err *errs.AppError) { + var status string + var charges bool + var remark = "" + secretKey, ok := l.ctx.Value("secretKey").(string) + if !ok { + return "", errs.ErrSystem + } + transactionID, ok := l.ctx.Value("transactionID").(string) + if !ok { + return "", errs.ErrSystem + } + userId, userIdOk := l.ctx.Value("userId").(int64) + if !userIdOk { + return "", errs.ErrSystem + } + productCode, productCodeOk := l.ctx.Value("productCode").(string) + if !productCodeOk || productCode == "" { + return "", errs.ErrSystem + } + + defer func() { + if err != nil { + status = "failed" + charges = false + } else { + status = "success" + charges = true + } + sendApiRequestMessageErr := l.svcCtx.ApiRequestMqsService.SendApiRequestMessage(l.ctx, transactionID, userId, productCode, status, charges, remark) + if sendApiRequestMessageErr != nil { + logx.Errorf("发送 API 请求消息失败: %v", err) + } + }() + // 1、解密 + key, decodeErr := hex.DecodeString(secretKey) + if decodeErr != nil { + return "", errs.ErrSystem + } + decryptData, aesDecryptErr := crypto.AesDecrypt(req.Data, key) + if aesDecryptErr != nil || len(decryptData) == 0 { + return "", errs.ErrParamDecryption + } + + // 2、校验 + var data validator.FLXG0V4BRequest + if validatorErr := validator.ValidateAndParse(decryptData, &data); validatorErr != nil { + return "", errs.ErrParamValidation + } + + // 3、西部加密 + westConfig := l.svcCtx.Config.WestConfig + encryptedFields, encryptStructFieldsErr := common.EncryptStructFields(data, westConfig.Key) + if encryptStructFieldsErr != nil { + logx.Errorf("西部加密错误:%v", encryptStructFieldsErr) + return "", errs.ErrSystem + } + + // 4、发送请求到西部 + logx.Infof("交易号:%s", transactionID) + apiRequest := common.MapStructToAPIRequest(encryptedFields, westmodel.FLXG0V4BFieldMapping, "data") + + westResp, callAPIErr := l.svcCtx.WestDexService.CallAPI("G22SC01", apiRequest, l.svcCtx.Config.WestConfig.SecretId) + if callAPIErr != nil { + if callAPIErr.Code == errs.ErrDataSource.Code { + encryptData, aesEncrypt := crypto.AesEncrypt(westResp, key) + if aesEncrypt != nil { + return "", errs.ErrSystem + } + return encryptData, callAPIErr + } + return "", callAPIErr + } + + encryptData, aesEncrypt := crypto.AesEncrypt(westResp, key) + if aesEncrypt != nil { + return "", errs.ErrSystem + } + return encryptData, nil +} diff --git a/apps/api/internal/logic/QYGL/qygl8271logic.go b/apps/api/internal/logic/QYGL/qygl8271logic.go new file mode 100644 index 0000000..7cbb375 --- /dev/null +++ b/apps/api/internal/logic/QYGL/qygl8271logic.go @@ -0,0 +1,111 @@ +package QYGL + +import ( + "context" + "encoding/hex" + + "tianyuan-api/apps/api/internal/common" + "tianyuan-api/apps/api/internal/svc" + "tianyuan-api/apps/api/internal/types" + "tianyuan-api/apps/api/internal/validator" + "tianyuan-api/apps/api/internal/westmodel" + "tianyuan-api/pkg/crypto" + "tianyuan-api/pkg/errs" + + "github.com/zeromicro/go-zero/core/logx" +) + +type QYGL8271Logic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewQYGL8271Logic(ctx context.Context, svcCtx *svc.ServiceContext) *QYGL8271Logic { + return &QYGL8271Logic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *QYGL8271Logic) QYGL8271(req *types.Request) (resp string, err *errs.AppError) { + var status string + var charges bool + var remark = "" + secretKey, ok := l.ctx.Value("secretKey").(string) + if !ok { + return "", errs.ErrSystem + } + transactionID, ok := l.ctx.Value("transactionID").(string) + if !ok { + return "", errs.ErrSystem + } + userId, userIdOk := l.ctx.Value("userId").(int64) + if !userIdOk { + return "", errs.ErrSystem + } + productCode, productCodeOk := l.ctx.Value("productCode").(string) + if !productCodeOk || productCode == "" { + return "", errs.ErrSystem + } + + defer func() { + if err != nil { + status = "failed" + charges = false + } else { + status = "success" + charges = true + } + sendApiRequestMessageErr := l.svcCtx.ApiRequestMqsService.SendApiRequestMessage(l.ctx, transactionID, userId, productCode, status, charges, remark) + if sendApiRequestMessageErr != nil { + logx.Errorf("发送 API 请求消息失败: %v", err) + } + }() + // 1、解密 + key, decodeErr := hex.DecodeString(secretKey) + if decodeErr != nil { + return "", errs.ErrSystem + } + decryptData, aesDecryptErr := crypto.AesDecrypt(req.Data, key) + if aesDecryptErr != nil || len(decryptData) == 0 { + return "", errs.ErrParamDecryption + } + + // 2、校验 + var data validator.QYGL8271Request + if validatorErr := validator.ValidateAndParse(decryptData, &data); validatorErr != nil { + return "", errs.ErrParamValidation + } + + // 3、西部加密 + westConfig := l.svcCtx.Config.WestConfig + encryptedFields, encryptStructFieldsErr := common.EncryptStructFields(data, westConfig.Key) + if encryptStructFieldsErr != nil { + logx.Errorf("西部加密错误:%v", encryptStructFieldsErr) + return "", errs.ErrSystem + } + + // 4、发送请求到西部 + logx.Infof("交易号:%s", transactionID) + apiRequest := common.MapStructToAPIRequest(encryptedFields, westmodel.QYGL8271FieldMapping, "data") + + westResp, callAPIErr := l.svcCtx.WestDexService.CallAPI("Q03SC01", apiRequest, l.svcCtx.Config.WestConfig.SecretId) + if callAPIErr != nil { + if callAPIErr.Code == errs.ErrDataSource.Code { + encryptData, aesEncrypt := crypto.AesEncrypt(westResp, key) + if aesEncrypt != nil { + return "", errs.ErrSystem + } + return encryptData, callAPIErr + } + return "", callAPIErr + } + + encryptData, aesEncrypt := crypto.AesEncrypt(westResp, key) + if aesEncrypt != nil { + return "", errs.ErrSystem + } + return encryptData, nil +} diff --git a/apps/api/internal/types/types.go b/apps/api/internal/types/types.go index 8406a6f..9fb1f77 100644 --- a/apps/api/internal/types/types.go +++ b/apps/api/internal/types/types.go @@ -1,5 +1,5 @@ // Code generated by goctl. DO NOT EDIT. -// goctl 1.7.2 +// goctl 1.7.3 package types diff --git a/apps/api/internal/validator/error_messages.go b/apps/api/internal/validator/error_messages.go index cb35e2c..02e18ac 100644 --- a/apps/api/internal/validator/error_messages.go +++ b/apps/api/internal/validator/error_messages.go @@ -12,6 +12,7 @@ var customMessages = map[string]string{ "ID.required": "id_card 是必填项", "ID.validID": "id 必须为有效的身份证号码", "TimeRange.validTimeRange": "time_range 必须为1到5的数字,表示年", + "AuthDate.validAuthDate": "auth_date 日期范围格式必须为yyyyMMdd-yyyyMMdd,范围不超过5年,且当前时间必须在范围内", } // 获取自定义错误消息 diff --git a/apps/api/internal/validator/structs.go b/apps/api/internal/validator/structs.go index 33bac13..58bc272 100644 --- a/apps/api/internal/validator/structs.go +++ b/apps/api/internal/validator/structs.go @@ -25,6 +25,11 @@ type FLXG0V3BRequest struct { IDCard string `json:"id_card" validate:"required,validIDCard"` Name string `json:"name" validate:"required,min=1,validName"` } +type FLXG0V4BRequest struct { + IDCard string `json:"id_card" validate:"required,validIDCard"` + Name string `json:"name" validate:"required,min=1,validName"` + AuthData string `json:"auth_data" validate:"required,validAuthData"` +} type FLXG54F5Request struct { MobileNo string `json:"mobile_no" validate:"required,min=11,max=11,validMobileNo"` } @@ -114,6 +119,11 @@ type QYGL45BDRequest struct { type QYGL8261Request struct { EntName string `json:"ent_name" validate:"required,min=1,validName"` } +type QYGL8271Request struct { + EntName string `json:"ent_name" validate:"required,min=1,validName"` + EntCode string `json:"ent_code" validate:"required,validUSCI"` + AuthDate string `json:"auth_date" validate:"required,validAuthDate"` +} type QYGLB4C0Request struct { IDCard string `json:"id_card" validate:"required,validIDCard"` } diff --git a/apps/api/internal/validator/validator.go b/apps/api/internal/validator/validator.go index 0fcad7f..75df93c 100644 --- a/apps/api/internal/validator/validator.go +++ b/apps/api/internal/validator/validator.go @@ -4,9 +4,12 @@ import ( "encoding/json" "errors" "fmt" - "github.com/go-playground/validator/v10" "regexp" "strconv" + "strings" + "time" + + "github.com/go-playground/validator/v10" ) var validate *validator.Validate @@ -50,6 +53,11 @@ func init() { if err := validate.RegisterValidation("validMobileType", validMobileType); err != nil { panic(fmt.Sprintf("注册 validMobileType 验证器时发生错误: %v", err)) } + + // 注册自定义验证器 validAuthDate + if err := validate.RegisterValidation("validAuthDate", validAuthDate); err != nil { + panic(fmt.Sprintf("注册 validAuthDate 验证器时发生错误: %v", err)) + } } // ValidateAndParse 封装了解密、解析和校验逻辑 @@ -73,6 +81,54 @@ func ValidateAndParse(decryptData []byte, req interface{}) error { return nil } +func ValidateAuthDate(date string) error { + // 校验日期格式是否为 yyyyMMdd-yyyyMMdd + validDateRangePattern := `^\d{4}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])-\d{4}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$` + matched, _ := regexp.MatchString(validDateRangePattern, date) + if !matched { + return errors.New("日期范围格式错误,应为yyyyMMdd-yyyyMMdd") + } + + // 分割开始和结束日期 + parts := strings.Split(date, "-") + if len(parts) != 2 { + return errors.New("日期范围格式错误,应为yyyyMMdd-yyyyMMdd") + } + + startDateStr, endDateStr := parts[0], parts[1] + + // 解析开始日期 + startDate, err := time.Parse("20060102", startDateStr) + if err != nil { + return errors.New("开始日期格式错误") + } + + // 解析结束日期 + endDate, err := time.Parse("20060102", endDateStr) + if err != nil { + return errors.New("结束日期格式错误") + } + + // 校验开始日期不大于结束日期 + if startDate.After(endDate) { + return errors.New("开始日期不能大于结束日期") + } + + // 校验时间范围不能超过5年 + maxDuration := 5 * 365 * 24 * time.Hour // 5年的近似时间(不考虑闰年) + if endDate.Sub(startDate) > maxDuration { + return errors.New("时间范围不能超过5年") + } + + // 校验当前时间在范围内 + now := time.Now() + if now.Before(startDate) || now.After(endDate) { + return errors.New("当前时间必须在指定的时间范围内") + } + + return nil +} + // 获取验证器实例 func GetValidator() *validator.Validate { return validate @@ -154,3 +210,15 @@ func validMobileType(fl validator.FieldLevel) bool { return validTypes[mobileType] } + +// 自定义的日期范围验证器(用于结构体字段验证) +func validAuthDate(fl validator.FieldLevel) bool { + dateRange := fl.Field().String() + // 如果是空字符串,认为是有效的(非必填项) + if dateRange == "" { + return true + } + + err := ValidateAuthDate(dateRange) + return err == nil +} diff --git a/apps/api/internal/westmodel/fieldMapping.go b/apps/api/internal/westmodel/fieldMapping.go index b14a0d6..53c12e7 100644 --- a/apps/api/internal/westmodel/fieldMapping.go +++ b/apps/api/internal/westmodel/fieldMapping.go @@ -10,6 +10,11 @@ var FLXG0V3BFieldMapping = map[string]string{ "IDCard": "id_card", "Name": "name", } +var FLXG0V4BFieldMapping = map[string]string{ + "IDCard": "idcard", + "Name": "name", + "AuthDate": "inquired_auth", +} var FLXG54F5FieldMapping = map[string]string{ "MobileNo": "mobile", } @@ -99,6 +104,11 @@ var QYGL45BDFieldMapping = map[string]string{ var QYGL8261FieldMapping = map[string]string{ "EntName": "ent_name", } +var QYGL8271FieldMapping = map[string]string{ + "EntName": "org_name", + "EntCode": "uscc", + "AuthDate": "inquired_auth", +} var QYGLB4C0FieldMapping = map[string]string{ "IDCard": "pid", } diff --git a/apps/gateway/internal/validator/validator.go b/apps/gateway/internal/validator/validator.go index 8d85a83..e9daf4d 100644 --- a/apps/gateway/internal/validator/validator.go +++ b/apps/gateway/internal/validator/validator.go @@ -32,6 +32,7 @@ func ValidatePhoneNumber(phone string) error { } return nil } + func ValidateVerifyCode(redisClient *redis.Redis, phone, code string) error { // 从 Redis 获取验证码 savedCode, err := redisClient.Get(phone)