Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
app_id: your_app_id
app_key: your_app_key
sm4_key: your_sm4_key
access_token: your_access_token
token_type:
33 changes: 33 additions & 0 deletions controllers/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import (
"fmt"
"log"

"github.com/casibase/casibase/controllers/utils"
)

func main() {
// 加载配置文件
configPath := "../config.yaml"
fmt.Println("加载配置:", configPath)
err := utils.LoadConfig(configPath)
if err != nil {
log.Fatal("加载配置失败:", err)
}

resp, err := utils.RequestToken("your_token_url")
if err != nil {
fmt.Println("请求失败:", err)
return
}
err = utils.SaveConfig(configPath)
if err != nil {
fmt.Println("保存配置失败:", err)
return
}
fmt.Println("AccessToken:", resp.ResultData.AccessToken)
fmt.Println("TokenType:", resp.ResultData.TokenType)
// fmt.Println("全局变量AccessToken:", utils.AccessToken)
// fmt.Println("全局变量TokenType:", utils.TokenType)
}
111 changes: 111 additions & 0 deletions controllers/test_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package main

import (
"encoding/json"
"fmt"
"log"
"strings"
"time"

"github.com/casibase/casibase/controllers/utils"
)

func main() {
configPath := "../config.yaml"
err := utils.LoadConfig(configPath)
if err != nil {
log.Fatal("加载配置失败:", err)
}

// 检查token和type
if utils.AccessToken == "" || utils.TokenType == "" {
log.Fatal("access_token或token_type未设置")
}

now := time.Now()
// 格式化为 "yyyyMMddHHmmss" 格式
timestamp := now.Format("20060102150405")

// 序列化biz
bizContentJson, err := json.Marshal(utils.BizContent{
UserName: "admin",
DepCode: "admin",
})
if err != nil {
panic(err)
}

bizContent := strings.ReplaceAll(string(bizContentJson), `\`, "")
// 对bizContent中的key进行排序
var bizMap map[string]interface{}
if err := json.Unmarshal([]byte(bizContent), &bizMap); err != nil {
panic(err)
}
orderedBizContent, err := json.Marshal(map[string]interface{}{
"userName": bizMap["userName"],
"depCode": bizMap["depCode"],
})
if err != nil {
panic(err)
}
bizContent = string(orderedBizContent)
nonceStr, err := utils.RandomString(32)
// 构造请求体(不带sign)
req := utils.ServiceRequest{
Timestamp: timestamp,
SignType: "signtype",
EncType: "encType",
DataType: "dataType",
Method: "method",
Version: "v1.0",
AppId: "appId",
ApiCaller: "apiCaller",
BizContent: bizMap,
NonceStr: nonceStr,
// Sign: 先不填
}
// reqJson, err := json.Marshal(req)
// if err != nil {
// panic(err)
// }
// 生成签名
sign, err := utils.GenerateSign(req)
if err != nil {
panic(err)
}

// 此时req即可用于请求
encStr, err := utils.EncryptStructToBase64(utils.BizContent{
UserName: "userName",
DepCode: "depCode",
})
if err != nil {
panic(err)
}

req2 := utils.SendRequest{
Timestamp: timestamp,
SignType: "signtype",
EncType: "encType",
DataType: "dataType",
Method: "method",
Version: "v1.0",
AppId: "appId",
ApiCaller: "apiCaller",
BizContent: encStr,
NonceStr: nonceStr,
Sign: sign,
}
// return
respBody, err := utils.CallServiceAPI(
"your_url",
utils.TokenType,
utils.AccessToken,
req2,
)
if err != nil {
fmt.Println("请求失败:", err)
return
}
fmt.Println("返回内容:", string(respBody))
}
66 changes: 66 additions & 0 deletions controllers/utils/json2m3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package utils

import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"sort"
"strings"

"github.com/tjfoc/gmsm/sm3"
)

// 递归序列化结构体为map[string]interface{}
func StructToMap(obj interface{}) (map[string]interface{}, error) {
var m map[string]interface{}
data, err := json.Marshal(obj)
if err != nil {
return nil, err
}
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.UseNumber()
if err := decoder.Decode(&m); err != nil {
return nil, err
}
return m, nil
}

// 排除sign字段,并格式化为JSON字符串
func GenSignString(obj interface{}) (string, error) {
// 将对象转换为JSON字符串
jsonBytes, err := json.Marshal(obj)
if err != nil {
return "", err
}
jsonStr := string(jsonBytes)
jsonStr = strings.ReplaceAll(jsonStr, `\`, "")
fmt.Println("\n")
fmt.Println("jsonStr:", jsonStr)
fmt.Println("\n")
// 按逗号分割
parts := strings.Split(jsonStr, ",")

// 排序
sort.Strings(parts)
// 拼接结果
result := strings.Join(parts, "")
result = strings.ReplaceAll(result, `\`, "")
fmt.Println("sorted:", result)
return result, nil
}

// 生成SM3签名并返回base64
func SM3Base64(str string) string {
sum := sm3.Sm3Sum([]byte(str))
return base64.StdEncoding.EncodeToString(sum)
}

// 一步到位签名生成
func GenerateSign(obj interface{}) (string, error) {
signStr, err := GenSignString(obj)
if err != nil {
return "", err
}
return SM3Base64(signStr), nil
}
25 changes: 25 additions & 0 deletions controllers/utils/random_nonce_str.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package utils

import (
"crypto/rand"
"fmt"
"math/big"
)

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

// RandomString 生成指定长度的随机字符串
func RandomString(n int) (string, error) {
if n <= 0 || n > 32 {
return "", fmt.Errorf("长度必须在 1 到 32 之间")
}
result := make([]byte, n)
for i := range result {
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letterBytes))))
if err != nil {
return "", err
}
result[i] = letterBytes[num.Int64()]
}
return string(result), nil
}
95 changes: 95 additions & 0 deletions controllers/utils/struct2m4.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package utils

import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"reflect"
"strings"

"github.com/tjfoc/gmsm/sm4"
)

// 结构体转 map[string]string
func structToMap(obj interface{}) (map[string]string, error) {
v := reflect.ValueOf(obj)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return nil, errors.New("input is not a struct")
}
t := v.Type()
result := make(map[string]string)
for i := 0; i < v.NumField(); i++ {
field := t.Field(i)
key := field.Tag.Get("json")
if key == "" {
key = field.Name
}
val := v.Field(i).Interface()
switch value := val.(type) {
case string:
result[key] = value
default:
b, _ := json.Marshal(value)
result[key] = string(b)
}
}
return result, nil
}

func pkcs7Pad(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}

func sm4EncryptBase64(plainText []byte, key []byte) (string, error) {
block, err := sm4.NewCipher(key)
if err != nil {
return "", err
}
padded := pkcs7Pad(plainText, block.BlockSize())
encrypted := make([]byte, len(padded))
for bs := 0; bs < len(padded); bs += block.BlockSize() {
block.Encrypt(encrypted[bs:bs+block.BlockSize()], padded[bs:bs+block.BlockSize()])
}
return base64.StdEncoding.EncodeToString(encrypted), nil
}

// SM4加密函数
func EncryptStructToBase64(data interface{}) (string, error) {
// 将结构体转换为map
param, err := structToMap(data)
if err != nil {
return "", err
}
fmt.Println("param:", param)
paramJson, err := json.Marshal(param)
if err != nil {
return "", err
}
paramStr := string(paramJson)
paramStr = strings.ReplaceAll(paramStr, `\`, "")
fmt.Println("paramStr:", paramStr)
cipherBase64, err := sm4EncryptBase64([]byte(paramStr), Sm4Key)
if err != nil {
return "", err
}
fmt.Println("加密后Base64:", cipherBase64)
return cipherBase64, nil
// padded := pad([]byte(paramStr), 16)
// block, err := sm4.NewCipher(Sm4Key)
// if err != nil {
// return "", err
// }
// encrypted := make([]byte, len(padded))
// for bs := 0; bs < len(padded); bs += 16 {
// block.Encrypt(encrypted[bs:bs+16], padded[bs:bs+16])
// }
// encStr := base64.StdEncoding.EncodeToString(encrypted)
// return encStr, nil
}
Loading