设计目标
- 支持RSA2加签验签(解析密钥方式:PKCS1 数字签名算法:SHA256)
- 支持grpc拦截器加签验签,对业务代码无侵入
- 支持gin框架中间件验签,支持客户端发送http请求设置加签信息到Header中
- 支持服务端对接多语言客户端(签名原文为:有序JSON(ASCII码序排序Key,忽略结构体/Map中的0值和空值),RSA2加签(PKCS1+SHA256))
签名
签名接口
1 2 3 4 5 6 7 8 9 10 | 加签接口 func Sign(content, privateKey string)(sign string, err error) 验签接口 func Verify(content, sign, pubKey string) (err error) 结构体、Map等转换为JSON字符串接口 // InterfaceToSortedJSONStr 结构体、Map 转 待加签的排序的json字符串 // json按照字典序排序,值为空或者为0的忽略,不序列化为json的忽略(tag中`json:"-"`),不参与加签的字段忽略(tag中`sign:"-"`) func InterfaceToSortedJSONStr(i interface{}) (str string, err error) |
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | package signature import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/json" "encoding/pem" "errors" "fmt" "reflect" "sort" "strings" ) type SignType string const ( RSA2 SignType = "SHA256WithRSA" ) const InvalidType = "invalid type=%v" var ErrPemDecode = errors.New("pem.Decode failed") func NewRSASigner() *Signer { return &Signer{ Type: RSA2, } } type Signer struct { Type SignType } func (s *Signer) Sign(content, privateKey string) (sign string, err error) { if s.Type == RSA2 { return rsa2Sign(content, privateKey) } return } func rsa2Sign(content, privateKey string) (sign string, err error) { // 1、将密钥解析成密钥实例 block, _ := pem.Decode([]byte(privateKey)) if block == nil { err = ErrPemDecode return } key, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return } // 2、生成签名 hash := sha256.New() _, err = hash.Write([]byte(content)) if err != nil { return } signature, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hash.Sum(nil)) if err != nil { return } // 3、签名base64编码 sign = base64.StdEncoding.EncodeToString(signature) return } func NewRSAVerifier() *Verifier { return &Verifier{ Type: RSA2, } } type Verifier struct { Type SignType } func (s *Verifier) Verify(content, sign, pubKey string) (err error) { if s.Type == RSA2 { return rsa2Verify(content, sign, pubKey) } return } func rsa2Verify(content, sign, pubKey string) (err error) { // 1、签名base64解码 signature, err := base64.StdEncoding.DecodeString(sign) if err != nil { return } // 2、密钥解析成公钥实例 block, _ := pem.Decode([]byte(pubKey)) if block == nil { err = ErrPemDecode return } key, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return } hash := sha256.New() _, err = hash.Write([]byte(content)) if err != nil { return } // 3、验证签名 pub := key.(*rsa.PublicKey) err = rsa.VerifyPKCS1v15(pub, crypto.SHA256, hash.Sum(nil), signature) return } type ToSignMap map[string]interface{} func (sc ToSignMap) ToSortedNoZeroValue() ToSignMap { if len(sc) == 0 { return sc } // 1、取出sc的值不为空的key var keys []string for k, v := range sc { // 忽略空值 if k == "" || v == "" { continue } keys = append(keys, k) } // 2、排序 sort.Strings(keys) // 3、重组为排序的map sorted := make(ToSignMap) for _, v := range keys { sorted[v] = sc[v] } return sorted } func (sc ToSignMap) ToSortedNoZeroValueJSON() (content string, err error) { sorted := sc.ToSortedNoZeroValue() if len(sorted) == 0 { return } // 转换为Json js, err := json.Marshal(sorted) if err != nil { return } content = string(js) return } // InterfaceToSortedJSONStr 结构体、Map 转 待加签的排序的json字符串 // json按照字典序排序,值为空或者为0的忽略,不序列化为json的忽略(tag中`json:"-"`),不参与加签的字段忽略(tag中`sign:"-"`) func InterfaceToSortedJSONStr(i interface{}) (str string, err error) { // 1、数据提取,基础类型提取值,结构体、Map等转换为有序Map if i == nil { err = fmt.Errorf(InvalidType, i) return } v, err := interfaceValExtract(i) if err != nil { return } // 2、字符串类型直接返回 if vStr, ok := v.(string); ok { str = vStr return } // 3、序列化为json js, err := json.Marshal(v) if err != nil { return } str = string(js) return } // interfaceValExtract 提取i的值,i为0值或空值时返回"",结构体、Map 转 key排序的Map[string]interface{} func interfaceValExtract(i interface{}) (v interface{}, err error) { // 1、构建默认返回值,反射获取i的类型与值 v = "" typ := reflect.TypeOf(i) val := reflect.ValueOf(i) // 2、指针类型取出元素类型与值 if typ.Kind() == reflect.Ptr { if val.IsNil() { return } typ = typ.Elem() val = val.Elem() } // 3、分类型处理 k := typ.Kind() switch k { case reflect.Bool: v = val.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: // 忽略0值 if val.Int() == 0 { return } v = val.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: // 忽略0值 if val.Uint() == 0 { return } v = val.Uint() case reflect.Float32, reflect.Float64: if val.IsZero() { return } v = val.Float() case reflect.String: v = val.String() case reflect.Slice, reflect.Array: if val.Len() == 0 { return } v, err = sliceValExtract(val) case reflect.Struct: if val.IsZero() { return } v, err = structValToSortedMap(typ, val) case reflect.Map: if val.Len() == 0 { return } v, err = mapValToSortedMap(val) // 其他类型不参与签名 default: err = fmt.Errorf(InvalidType, k) } return } // structValToSortedMap 结构体转排序的json string,忽略空值和0值 func structValToSortedMap(typs reflect.Type, vals reflect.Value) (sc ToSignMap, err error) { // 1、构建map sc = make(ToSignMap) // 2、反射遍历属性 num := vals.NumField() for i := 0; i < num; i++ { val := vals.Field(i) typ := typs.Field(i) // 判断是否为需要忽略的加签字段 if isSkippedSignField(typ.Tag) { continue } // 判断属性是否可导出(私有属性不能导出) if !val.CanInterface() { continue } // 转换成排序类型 var v interface{} v, err = interfaceValExtract(val.Interface()) if err != nil { return } // 名称以结构体中的json标签名称为准 name := typ.Name if jsonName := getJSONNameInTag(typ.Tag); jsonName != "" { name = jsonName } sc[name] = v } // 3、元素排序、去掉空值 sc = sc.ToSortedNoZeroValue() return } func isSkippedSignField(tag reflect.StructTag) bool { // 1、忽略不序列化的字段 v, ok := tag.Lookup("json") if ok && v == "-" { return true } // 2、忽略不加签的字段 v, ok = tag.Lookup("sign") return ok && v == "-" } func getJSONNameInTag(tag reflect.StructTag) string { v, ok := tag.Lookup("json") if ok { return strings.Split(v, ",")[0] } return "" } // mapValToSortedMap map转排序的json string,忽略0值和空值 func mapValToSortedMap(vals reflect.Value) (sc ToSignMap, err error) { // 1、构建map sc = make(ToSignMap) // 2、反射遍历属性 iter := vals.MapRange() for iter.Next() { // 处理key key, er := interfaceValExtract(iter.Key().Interface()) if er != nil { err = er return } k := fmt.Sprintf("%v", key) // 处理value var val interface{} val, err = interfaceValExtract(iter.Value().Interface()) if err != nil { return } // 赋值 sc[k] = val } // 3、元素排序、去掉空值 sc = sc.ToSortedNoZeroValue() return } // sliceValExtract 切片转忽略空值 或 配置了忽略签名 的切片 func sliceValExtract(vals reflect.Value) (s []interface{}, err error) { // 1、反射遍历属性 num := vals.Len() for i := 0; i < num; i++ { // 类型判断 val := vals.Index(i) k := val.Kind() if isNotValidType(k) { err = fmt.Errorf(InvalidType, k) return } // 判断属性是否可导出(私有属性不能导出) if !val.CanInterface() { continue } // 取出值 v := val.Interface() // 结构体/Map/切片类型进行值的提取 if k == reflect.Struct || k == reflect.Map || k == reflect.Slice || k == reflect.Array { // 提取切片的元素 v, err = interfaceValExtract(val.Interface()) if err != nil { return } } s = append(s, v) } // 2、返回处理后的切片 return } func isNotValidType(k reflect.Kind) bool { return k == reflect.Invalid || k == reflect.Complex64 || k == reflect.Complex128 || k == reflect.Chan || k == reflect.Func || k == reflect.UnsafePointer } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | package signature import ( "testing" "github.com/stretchr/testify/assert" ) type ProtoTest struct { ID int `protobuf:"varint,1,opt,name=offset,proto3" json:"id" sign:"-"` Flag bool `protobuf:"varint,1,opt,name=offset,proto3" json:"flag"` Dou float32 `protobuf:"varint,1,opt,name=offset,proto3" json:"dou"` Str string `protobuf:"varint,1,opt,name=offset,proto3" json:"str"` Val1 map[int]string `protobuf:"varint,1,opt,name=offset,proto3" json:"val1"` Val2 map[string]string `protobuf:"varint,1,opt,name=offset,proto3" json:"val2"` Val3 []map[string]InnerTest1 `protobuf:"varint,1,opt,name=offset,proto3" json:"val3"` Val4 [][]map[string]InnerTest1 `protobuf:"varint,1,opt,name=offset,proto3" json:"val4"` Arr []InnerTest1 `protobuf:"varint,1,opt,name=offset,proto3" json:"arr"` Arr1 []int `protobuf:"varint,1,opt,name=offset,proto3" json:"arr1"` Inner InnerTest1 `protobuf:"varint,1,opt,name=offset,proto3" json:"inner"` Inner1 InnerTest1 `protobuf:"varint,1,opt,name=offset,proto3" json:"inner1"` Flags []bool `protobuf:"varint,1,opt,name=offset,proto3" json:"flags"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } type InnerTest1 struct { Val map[string]string `protobuf:"varint,1,opt,name=offset,proto3" json:"val" sign:"-"` Inner *InnerTest2 `protobuf:"varint,1,opt,name=offset,proto3" json:"inner"` } type InnerTest2 struct { ID int `protobuf:"varint,1,opt,name=offset,proto3" json:"id"` } var ( innerTest1 = InnerTest1{ Val: map[string]string{ "a": "a", "b": "b", }, Inner: &InnerTest2{ ID: 1, }, } pt = &ProtoTest{ ID: 1, Val1: map[int]string{ 1: "1", 2: "2", }, Val2: map[string]string{ "a": "a", "b": "b", }, Val3: []map[string]InnerTest1{{"val3": innerTest1}}, Val4: [][]map[string]InnerTest1{{{"val4": innerTest1}}}, Arr: []InnerTest1{innerTest1}, Arr1: []int{1, 0, 3, 2, 4}, Inner: innerTest1, Flags: []bool{true, false}, } mt = map[string]interface{}{ "id": 1, "dou": 3.14, "pt": pt, "str": "str", "strEmpty": "", "": 1, } ) const jsonStr = `{"dou":3.14,"id":1,"pt":{"arr":[{"inner":{"id":1}}],"flag":false,"flags":[true,false],"inner":{"inner":{"id":1}},"val1":{"1":"1","2":"2"},"val2":{"a":"a","b":"b"}},"str":"str"}` func TestInterfaceToSortedJsonStr(t *testing.T) { testAssert := assert.New(t) tests := []struct { origin interface{} sign string }{ {pt, `{"arr":[{"inner":{"id":1}}],"arr1":[1,0,3,2,4],"flag":false,"flags":[true,false],"inner":{"inner":{"id":1}},"val1":{"1":"1","2":"2"},"val2":{"a":"a","b":"b"},"val3":[{"val3":{"inner":{"id":1}}}],"val4":[[{"val4":{"inner":{"id":1}}}]]}`}, {mt, `{"dou":3.14,"id":1,"pt":{"arr":[{"inner":{"id":1}}],"arr1":[1,0,3,2,4],"flag":false,"flags":[true,false],"inner":{"inner":{"id":1}},"val1":{"1":"1","2":"2"},"val2":{"a":"a","b":"b"},"val3":[{"val3":{"inner":{"id":1}}}],"val4":[[{"val4":{"inner":{"id":1}}}]]},"str":"str"}`}, {jsonStr, jsonStr}, {1, "1"}, {false, "false"}, {"", ""}, } for _, test := range tests { sign, err := InterfaceToSortedJSONStr(test.origin) testAssert.Equal(sign, test.sign) testAssert.Equal(err, nil) } } const ( rsaPrivateKey = ` -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQCY4/TH2UpkW5pRgdmvkwGQGWFt1E2a76j9s1gmm0wOiByLQ1KQ NuJ1c3SBpAKcIMh4841cf3t1HPTttgaK/51RGq7AN+R7naKnFWg20WGzkEpHzS4E JM+S1bOtyz260ZhunxMA4HmmWPDq94lczfMEss/wjKL+r9R3HIeh21cKfwIDAQAB AoGAEanYaFRay2Bn4j3JvAaUWiUMhAdQlfNVR0Y2i3NKpK0l+xLikYW9wQr/LVEY +hexgYPF06doyH15cJMki19/uaawZLVRTv8tiTD+XHlpjFUpVlf52/be19gK+/ZL mqjs2WQggJMyzH/OvBnvkqxEpqf5ilIUAvJWgJ6wfYUBHhUCQQC3u2Map9scywhQ dzP4u0INvFKKrgz2O64uwf7Gn5rbXRsDTl8tLUXoiGiOGNjNtX/y4CeLjRn5ezs+ ZDm4EHddAkEA1QcHPnjzusJogGvy8iSVfqTDbby+KzhTYxMFaaA0q4r91Kz1BVP+ kc47n24G3y3Zhs5rro78loRpdJOeUfJ3iwJAFbxEUB31bOWT+Tjw3AcDHG7f8OoA PIz44S0v/71X64WLMYvu9IA7mfOxMsY7t7I2Dbx40SiDHyF1876VmXHRPQJAVSI0 6+uMhBOTjdcWRV0HfZA9JcrrOPyOnqaIYDkNM40defQRC6sQrpZ7z3A6QNDjAPPX pvAv07thJZylBdzflwJABTzHbnZ+R6av1Qz8zsicHAC6YG1PuprXO40X/Icl8W+D yNwv2bKrpA9MxS2bFcC9wtVeeWgE1oyJBJD8pEQonQ== -----END RSA PRIVATE KEY----- ` rsaPubKey = ` -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCY4/TH2UpkW5pRgdmvkwGQGWFt 1E2a76j9s1gmm0wOiByLQ1KQNuJ1c3SBpAKcIMh4841cf3t1HPTttgaK/51RGq7A N+R7naKnFWg20WGzkEpHzS4EJM+S1bOtyz260ZhunxMA4HmmWPDq94lczfMEss/w jKL+r9R3HIeh21cKfwIDAQAB -----END PUBLIC KEY----- ` ) func TestSign(t *testing.T) { testAssert := assert.New(t) sign, err := sign() testAssert.Equal(sign, "lQuCpp3kW8udrTNtaKcGTPDeGelxIHEXqp4u3n1owDlFRQtbqKpPoLxICHt5ahEf4WvWiuoAqofJqv52/PhjPPKDWawMVZJlgP38bxkvD6Y1+pgXSvKSm+LXHpHQRExcLiHUvytWJ6U+C0geDoswdGMeHiRxT9IX6nWovKayZrk=") testAssert.Equal(err, nil) } func sign() (string, error) { str, _ := InterfaceToSortedJSONStr(mt) return NewRSASigner().Sign(str, rsaPrivateKey) } func TestVerify(t *testing.T) { testAssert := assert.New(t) str, _ := InterfaceToSortedJSONStr(pt) sign, _ := sign() err := NewRSAVerifier().Verify(str, sign, rsaPubKey) testAssert.Equal(err, nil) } |
中间件
名词解释
App:访问server端的应用
公共方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package signmiddleware import "xxx/signature" const ( SignAppIDKey = "appID" // app ID key, http请求时设置appID到Header中, grpc请求时client拦截器自动完成 设置到context中 SignValueKey = "sign" // 签名 key, http请求时设置sign到Header中, grpc请求时client拦截器自动完成 设置到context中 ErrAppIDorSign = "app id or sign is not valid, app id=%v" ) type SignClient struct { AppID string // app ID PrivateKey string // 私钥 } type GetPublicKeysByID func(appID string) ([]string, error) // CreateSign 生成签名 func CreateSign(request interface{}, privateKey string) (sign string, err error) { // 1、req转有序json toSignJSON, err := signature.InterfaceToSortedJSONStr(request) if err != nil { return } // 2、签名 sign, err = signature.NewRSASigner().Sign(toSignJSON, privateKey) return } // VerifySign 验证签名 func VerifySign(request interface{}, sign string, pubKeys []string) (err error) { // 1、req转有序json toSignJSON, err := signature.InterfaceToSortedJSONStr(request) if err != nil { return } // 2、支持多个公钥验签,密钥升级时,兼容旧的请求 verifier := signature.NewRSAVerifier() for _, v := range pubKeys { err = verifier.Verify(toSignJSON, sign, v) // 验签成功,跳出循环 if err == nil { break } } return } |
GRPC中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | package grpcsign import ( "context" "fmt" "xxx/signmiddleware" "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" "google.golang.org/grpc" ) func SignUnaryServerInterceptor(getPubKey signmiddleware.GetPublicKeysByID) grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { // 1、获取context中自定义的属性 appID := GetAppIDFromCtx(ctx) sign := getSignFromCtx(ctx) if appID == "" || sign == "" { return nil, fmt.Errorf(signmiddleware.ErrAppIDorSign, appID) } // 2、根据AppID获取公钥 pubKeys, err := getPubKey(appID) if err != nil { return nil, err } // 3、验证签名 err = signmiddleware.VerifySign(req, sign, pubKeys) // 验签失败 if err != nil { return nil, err } v, err := handler(ctx, req) return v, err } } func GetAppIDFromCtx(ctx context.Context) string { return metautils.ExtractIncoming(ctx).Get(signmiddleware.SignAppIDKey) } func getSignFromCtx(ctx context.Context) string { return metautils.ExtractIncoming(ctx).Get(signmiddleware.SignValueKey) } func SignUnaryClientInterceptor(signC *signmiddleware.SignClient) grpc.UnaryClientInterceptor { return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { // 1、生成签名 sign, err := signmiddleware.CreateSign(req, signC.PrivateKey) if err != nil { return err } // 3、appID及签名设置到context, grpc自定义key只能使用grpc提供的metadata接口 newCtx := metautils.ExtractOutgoing(ctx).Clone().Set(signmiddleware.SignAppIDKey, signC.AppID).Set(signmiddleware.SignValueKey, sign).ToOutgoing(ctx) // 4、调用服务端 err = invoker(newCtx, method, req, reply, cc, opts...) return err } } |
GIN中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | package ginsign import ( "bytes" "encoding/json" "fmt" "io/ioutil" "net/url" "xxx/log" "xxx/signature" "xxx/signmiddleware" "github.com/gin-gonic/gin" ) // SignClientToHeader http请求加签,设置签名内容到header中,客户端使用 func SignClientToHeader(header map[string]string, req interface{}, signC *signmiddleware.SignClient) (newHeader map[string]string, err error) { // 1、生成sign sign, err := signmiddleware.CreateSign(req, signC.PrivateKey) if err != nil { return } // 2、设置到Header中 if len(header) == 0 { header = make(map[string]string) } header[signmiddleware.SignAppIDKey] = signC.AppID header[signmiddleware.SignValueKey] = sign newHeader = header return } // SignServerVerify gin验签中间件 func SignServerVerify(c *gin.Context, getPubKeysByID signmiddleware.GetPublicKeysByID) (err error) { // 1、从header中取出签名内容 appID := c.GetHeader(signmiddleware.SignAppIDKey) sign := c.GetHeader(signmiddleware.SignValueKey) if appID == "" || sign == "" { log.Warningf(c, "client signature is invalid, appID=%v, sign=%v", appID, sign) err = fmt.Errorf(signmiddleware.ErrAppIDorSign, appID) return } // 2、根据App ID获取公钥 pubKeys, err := getPubKeysByID(appID) if err != nil { log.Warningf(c, "svc.GetAppNameByID failed, appID=%v, err=%v", appID, err) return } // 3、初始化待签内容, request中的参数转content var content string switch { case c.Request.Method == "GET": content, err = convertURLValToSignJSON(c.Request.Form) case c.ContentType() == "application/json": content, err = convertBodyToSignJSON(c) default: content, err = convertURLValToSignJSON(c.Request.PostForm) } if err != nil { return } // 4、验证签名 err = signmiddleware.VerifySign(content, sign, pubKeys) // 验签失败 if err != nil { log.Warningf(c, "sign.middleware.VerifySign failed, appID=%v, content=%v, sign=%v, err=%v", appID, content, sign, err) } return } func convertURLValToSignJSON(values url.Values) (content string, err error) { if len(values) == 0 { return } // 构建排序map sc := make(signature.ToSignMap) for k, v := range values { if len(v) == 0 { continue } sc[k] = v[0] } // 转换为JSON content, err = sc.ToSortedNoZeroValueJSON() return } func convertBodyToSignJSON(c *gin.Context) (content string, err error) { // 1、获取body []byte data, err := c.GetRawData() if err != nil { return } // 2、data转map content, err = jsonToSorted(data) // 3、重新赋值body,以便body可以被再次读取 c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) return } func jsonToSorted(data []byte) (content string, err error) { sc := make(signature.ToSignMap) err = json.Unmarshal(data, &sc) if err != nil { return } // 转换为有序JSON content, err = signature.InterfaceToSortedJSONStr(sc) return } |