From 85dea0570475d92258243caa0012430cc8cd6cf4 Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Wed, 2 Apr 2025 18:30:48 +0800 Subject: [PATCH] update ivyz5773 --- apps/api/etc/api-api.dev.yaml | 40 ++-- apps/api/etc/api-api.yaml | 40 ++-- apps/api/internal/config/config.go | 6 + apps/api/internal/logic/IVYZ/ivyz5733logic.go | 49 +++-- apps/api/internal/service/yushanService.go | 190 ++++++++++++++++++ apps/api/internal/svc/servicecontext.go | 11 +- go.mod | 3 + go.sum | 6 + pkg/errs/api.go | 1 + 9 files changed, 287 insertions(+), 59 deletions(-) create mode 100644 apps/api/internal/service/yushanService.go diff --git a/apps/api/etc/api-api.dev.yaml b/apps/api/etc/api-api.dev.yaml index 62478cc..39a94ac 100644 --- a/apps/api/etc/api-api.dev.yaml +++ b/apps/api/etc/api-api.dev.yaml @@ -3,25 +3,29 @@ Host: 0.0.0.0 Port: 10003 DataSource: "tianyuanapi:g3h98u0291j@tcp(127.0.0.1:3307)/tianyuanapi?charset=utf8mb4&parseTime=True&loc=Local" CacheRedis: - - Host: "127.0.0.1:6379" - Pass: "" # Redis 密码,如果未设置则留空 - Type: "node" # 单节点模式 + - Host: "127.0.0.1:6379" + Pass: "" # Redis 密码,如果未设置则留空 + Type: "node" # 单节点模式 SentinelRpc: - Etcd: - Hosts: - - 127.0.0.1:2379 - Key: sentinel.rpc + Etcd: + Hosts: + - 127.0.0.1:2379 + Key: sentinel.rpc KqPusherConf: - Brokers: - - 127.0.0.1:9092 - Topic: apirequest + Brokers: + - 127.0.0.1:9092 + Topic: apirequest WestConfig: - Url: "http://proxy.tianyuanapi.com/api/invoke" - Key: "121a1e41fc1690dd6b90afbcacd80cf4" - SecretId: "449159" - SecretSecondId: "296804" + Url: "http://proxy.tianyuanapi.com/api/invoke" + Key: "121a1e41fc1690dd6b90afbcacd80cf4" + SecretId: "449159" + SecretSecondId: "296804" +YushanConfig: + ApiKey: "4c566c4a4b543164535455685655316c" + AcctID: "YSSJ843926726" + Url: "https://api.yushanshuju.com/credit-gw/service" UserRpc: - Etcd: - Hosts: - - 127.0.0.1:2379 - Key: user.rpc \ No newline at end of file + Etcd: + Hosts: + - 127.0.0.1:2379 + Key: user.rpc diff --git a/apps/api/etc/api-api.yaml b/apps/api/etc/api-api.yaml index 3796cb5..2a5edf1 100644 --- a/apps/api/etc/api-api.yaml +++ b/apps/api/etc/api-api.yaml @@ -3,25 +3,29 @@ Host: 0.0.0.0 Port: 10003 DataSource: "tianyuanapi:g3h98u0291j@tcp(tyapi_mysql:3306)/tianyuanapi?charset=utf8mb4&parseTime=True&loc=Local" CacheRedis: - - Host: "tyapi_redis:6379" - Pass: "" # Redis 密码,如果未设置则留空 - Type: "node" # 单节点模式 + - Host: "tyapi_redis:6379" + Pass: "" # Redis 密码,如果未设置则留空 + Type: "node" # 单节点模式 SentinelRpc: - Etcd: - Hosts: - - tyapi_etcd:2379 - Key: sentinel.rpc + Etcd: + Hosts: + - tyapi_etcd:2379 + Key: sentinel.rpc UserRpc: - Etcd: - Hosts: - - tyapi_etcd:2379 - Key: user.rpc + Etcd: + Hosts: + - tyapi_etcd:2379 + Key: user.rpc KqPusherConf: - Brokers: - - tyapi_kafka:9092 - Topic: apirequest + Brokers: + - tyapi_kafka:9092 + Topic: apirequest WestConfig: - Url: "https://apimaster.westdex.com.cn/api/invoke" - Key: "121a1e41fc1690dd6b90afbcacd80cf4" - SecretId: "449159" - SecretSecondId: "296804" \ No newline at end of file + Url: "https://apimaster.westdex.com.cn/api/invoke" + Key: "121a1e41fc1690dd6b90afbcacd80cf4" + SecretId: "449159" + SecretSecondId: "296804" +YushanConfig: + ApiKey: "4c566c4a4b543164535455685655316c" + AcctID: "YSSJ843926726" + Url: "https://api.yushanshuju.com/credit-gw/service" diff --git a/apps/api/internal/config/config.go b/apps/api/internal/config/config.go index fa2b9a3..1377cb1 100644 --- a/apps/api/internal/config/config.go +++ b/apps/api/internal/config/config.go @@ -14,6 +14,7 @@ type Config struct { UserRpc zrpc.RpcClientConf KqPusherConf KqPusherConf WestConfig WestConfig + YushanConfig YushanConfig } type KqPusherConf struct { Brokers []string @@ -25,3 +26,8 @@ type WestConfig struct { SecretId string SecretSecondId string } +type YushanConfig struct { + ApiKey string + AcctID string + Url string +} diff --git a/apps/api/internal/logic/IVYZ/ivyz5733logic.go b/apps/api/internal/logic/IVYZ/ivyz5733logic.go index 3fc0acb..05e1ea3 100644 --- a/apps/api/internal/logic/IVYZ/ivyz5733logic.go +++ b/apps/api/internal/logic/IVYZ/ivyz5733logic.go @@ -4,11 +4,11 @@ import ( "context" "encoding/hex" "encoding/json" - "tianyuan-api/apps/api/internal/common" + "errors" + "tianyuan-api/apps/api/internal/service" "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" @@ -79,31 +79,42 @@ func (l *IVYZ5733Logic) IVYZ5733(req *types.Request) (resp string, err *errs.App } // 3、西部加密 - westConfig := l.svcCtx.Config.WestConfig - encryptedFields, encryptStructFieldsErr := common.EncryptStructFields(data, westConfig.Key) - if encryptStructFieldsErr != nil { - logx.Errorf("西部加密错误:%v", encryptStructFieldsErr) - return "", errs.ErrSystem - } + // 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.IVYZ5733FieldMapping, "data") + // apiRequest := common.MapStructToAPIRequest(encryptedFields, westmodel.IVYZ5733FieldMapping, "data") - westResp, callAPIErr := l.svcCtx.WestDexService.CallAPI("G09SC02", apiRequest, l.svcCtx.Config.WestConfig.SecretId) + // westResp, callAPIErr := l.svcCtx.WestDexService.CallAPI("G09SC02", 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 + // } + apiRequest := map[string]interface{}{ + "cardNo": data.IDCard, + "name": data.Name, + } + respData, callAPIErr := l.svcCtx.YushanService.Request("IDV044", apiRequest) if callAPIErr != nil { - if callAPIErr.Code == errs.ErrDataSource.Code { - encryptData, aesEncrypt := crypto.AesEncrypt(westResp, key) - if aesEncrypt != nil { - return "", errs.ErrSystem - } - - return encryptData, callAPIErr + if errors.Is(callAPIErr, service.NotFound) { + return "", errs.ErrNotFound } - return "", callAPIErr + return "", errs.ErrSystem } - encryptData, aesEncrypt := crypto.AesEncrypt(westResp, key) + encryptData, aesEncrypt := crypto.AesEncrypt(respData, key) if aesEncrypt != nil { return "", errs.ErrSystem } diff --git a/apps/api/internal/service/yushanService.go b/apps/api/internal/service/yushanService.go new file mode 100644 index 0000000..99a4ba6 --- /dev/null +++ b/apps/api/internal/service/yushanService.go @@ -0,0 +1,190 @@ +package service + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "tianyuan-api/apps/api/internal/config" + "time" + + "github.com/tidwall/gjson" +) + +var NotFound = fmt.Errorf("查询为空") + +type YushanService struct { + config config.YushanConfig +} + +func NewYushanService(c config.YushanConfig) *YushanService { + return &YushanService{ + config: c, + } +} + +func (y *YushanService) Request(prodID string, params map[string]interface{}) ([]byte, error) { + // 获取当前时间戳 + unixMilliseconds := time.Now().UnixNano() / int64(time.Millisecond) + + // 生成请求序列号 + requestSN, _ := y.GenerateRandomString() + + // 构建请求数据 + reqData := map[string]interface{}{ + "prod_id": prodID, + "req_time": unixMilliseconds, + "request_sn": requestSN, + "req_data": params, + } + + // 将请求数据转换为 JSON 字节数组 + messageBytes, err := json.Marshal(reqData) + if err != nil { + return nil, err + } + + // 获取 API 密钥 + key, err := hex.DecodeString(y.config.ApiKey) + if err != nil { + return nil, err + } + + // 使用 AES CBC 加密请求数据 + cipherText := y.AES_CBC_Encrypt(messageBytes, key) + + // 将加密后的数据编码为 Base64 字符串 + content := base64.StdEncoding.EncodeToString(cipherText) + + // 发起 HTTP 请求 + client := &http.Client{} + req, err := http.NewRequest("POST", y.config.Url, strings.NewReader(content)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("ACCT_ID", y.config.AcctID) + + // 执行请求 + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + // 读取响应体 + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var respData []byte + + if IsJSON(string(body)) { + respData = body + } else { + sDec, err := base64.StdEncoding.DecodeString(string(body)) + if err != nil { + return nil, err + } + respData = y.AES_CBC_Decrypt(sDec, key) + } + retCode := gjson.GetBytes(respData, "retcode").String() + + if retCode == "100000" { + // retcode 为 100000,表示查询为空 + // return nil, fmt.Errorf("羽山请求查空: %s", string(respData)) + return nil, NotFound + } else if retCode == "000000" { + // retcode 为 000000,表示有数据,返回 retdata + retData := gjson.GetBytes(respData, "retdata") + if !retData.Exists() { + return nil, fmt.Errorf("羽山请求retdata为空: %s", string(respData)) + } + return []byte(retData.Raw), nil + } else { + return nil, fmt.Errorf("羽山请求未知的状态码: %s", string(respData)) + } + +} + +// 判断字符串是否为 JSON 格式 +func IsJSON(s string) bool { + var js interface{} + return json.Unmarshal([]byte(s), &js) == nil +} + +// GenerateRandomString 生成一个32位的随机字符串订单号 +func (y *YushanService) GenerateRandomString() (string, error) { + // 创建一个16字节的数组 + bytes := make([]byte, 16) + // 读取随机字节到数组中 + if _, err := rand.Read(bytes); err != nil { + return "", err + } + // 将字节数组编码为16进制字符串 + return hex.EncodeToString(bytes), nil +} + +// AEC加密(CBC模式) +func (y *YushanService) AES_CBC_Encrypt(plainText []byte, key []byte) []byte { + //指定加密算法,返回一个AES算法的Block接口对象 + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + //进行填充 + plainText = Padding(plainText, block.BlockSize()) + //指定初始向量vi,长度和block的块尺寸一致 + iv := []byte("0000000000000000") + //指定分组模式,返回一个BlockMode接口对象 + blockMode := cipher.NewCBCEncrypter(block, iv) + //加密连续数据库 + cipherText := make([]byte, len(plainText)) + blockMode.CryptBlocks(cipherText, plainText) + //返回base64密文 + return cipherText +} + +// AEC解密(CBC模式) +func (y *YushanService) AES_CBC_Decrypt(cipherText []byte, key []byte) []byte { + //指定解密算法,返回一个AES算法的Block接口对象 + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + //指定初始化向量IV,和加密的一致 + iv := []byte("0000000000000000") + //指定分组模式,返回一个BlockMode接口对象 + blockMode := cipher.NewCBCDecrypter(block, iv) + //解密 + plainText := make([]byte, len(cipherText)) + blockMode.CryptBlocks(plainText, cipherText) + //删除填充 + plainText = UnPadding(plainText) + return plainText +} // 对明文进行填充 +func Padding(plainText []byte, blockSize int) []byte { + //计算要填充的长度 + n := blockSize - len(plainText)%blockSize + //对原来的明文填充n个n + temp := bytes.Repeat([]byte{byte(n)}, n) + plainText = append(plainText, temp...) + return plainText +} + +// 对密文删除填充 +func UnPadding(cipherText []byte) []byte { + //取出密文最后一个字节end + end := cipherText[len(cipherText)-1] + //删除填充 + cipherText = cipherText[:len(cipherText)-int(end)] + return cipherText +} diff --git a/apps/api/internal/svc/servicecontext.go b/apps/api/internal/svc/servicecontext.go index 326a98c..fad7879 100644 --- a/apps/api/internal/svc/servicecontext.go +++ b/apps/api/internal/svc/servicecontext.go @@ -1,16 +1,17 @@ package svc import ( - "github.com/zeromicro/go-queue/kq" - "github.com/zeromicro/go-zero/core/stores/redis" - "github.com/zeromicro/go-zero/rest" - "github.com/zeromicro/go-zero/zrpc" "tianyuan-api/apps/api/internal/config" "tianyuan-api/apps/api/internal/middleware" "tianyuan-api/apps/api/internal/service" "tianyuan-api/apps/sentinel/sentinel" "tianyuan-api/apps/user/user" "time" + + "github.com/zeromicro/go-queue/kq" + "github.com/zeromicro/go-zero/core/stores/redis" + "github.com/zeromicro/go-zero/rest" + "github.com/zeromicro/go-zero/zrpc" ) type ServiceContext struct { @@ -23,6 +24,7 @@ type ServiceContext struct { ProductRpc sentinel.ProductClient UserProductRpc sentinel.UserProductClient WestDexService *service.WestDexService + YushanService *service.YushanService ApiRequestMqsService *service.ApiRequestMqsService } type ApiRequestMessage struct { @@ -61,5 +63,6 @@ func NewServiceContext(c config.Config) *ServiceContext { ApiMqsInterceptor: middleware.NewApiMqsInterceptorMiddleware(apiRequestMqsService).Handle, ApiRequestMqsService: apiRequestMqsService, WestDexService: service.NewWestDexService(c.WestConfig), // 假设你将密钥和 ID 配置在 config 中 + YushanService: service.NewYushanService(c.YushanConfig), } } diff --git a/go.mod b/go.mod index 7e88265..7d08861 100644 --- a/go.mod +++ b/go.mod @@ -82,6 +82,9 @@ require ( github.com/smartwalle/ngx v1.0.9 // indirect github.com/smartwalle/nsign v1.0.9 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/tidwall/gjson v1.18.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect github.com/tjfoc/gmsm v1.3.2 // indirect go.etcd.io/etcd/api/v3 v3.5.15 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect diff --git a/go.sum b/go.sum index b95d161..2564c97 100644 --- a/go.sum +++ b/go.sum @@ -269,6 +269,12 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= diff --git a/pkg/errs/api.go b/pkg/errs/api.go index bba2e4f..d3804f9 100644 --- a/pkg/errs/api.go +++ b/pkg/errs/api.go @@ -2,6 +2,7 @@ package errs // 常见错误 var ( + ErrNotFound = NewAppError(1000, "查询为空") ErrSystem = NewAppError(1001, "接口异常") ErrParamDecryption = NewAppError(1002, "参数解密失败") ErrParamValidation = NewAppError(1003, "基础参数校验不正确")