说明
客户端调用
正式服: 外网:https://comb-platform.hortorgames.com
测试服 外网:https://comb-platform-test.hortorgames.com
开发服 外网:https://comb-platform-dev.hortorgames.com
服务器调用
正式服: 外网:https://comb-sapi.hortorgames.com
测试服 外网:https://comb-sapi-test.hortorgames.com
开发服 外网:https://comb-sapi-dev.hortorgames.com
签名
签名字符串示例如下
sign = md5("content=a54456bf13582e773df04a35eab49ecbgameId=yydssecret=57a1fe2376ef483b2fa9cd1cbcf454f7timestamp=1639622430")
其中 content、gameId、secret、timestamp 在字符串中的顺序要严格按照上面示例中的顺序(字典序)
注意: 如果 query 里有其他参数, 也要参与签名, 并按照字典序排序
签名字符串中的content json 数据整个 body 进行 md5 加密作为 content
步骤
- 读取Request获取完整的Body请求参数
- 将body进行md5加密,得到content
- 读取Query参数form,并设置"content" = content,"secret" = secret
- 将参数按照字典序排序,拼接成字符串进行md5加密,得到sign
golang 示例
func CheckSign(c *gin.Context){
ctx := c.Request.Context()
body, err := io.ReadAll(c.Request.Body)
if err != nil {
resp.Error(err, c)
return
}
defer c.Request.Body.Close()
content = StringMd5(string(body))
data := c.Request.ParseForm()
data.Set("content", content)
if data.Get("sign") != SignWithSecret(data, secret) {
resp.Error(errors.New("签名错误"), c)
return
}
}
func SignWithSecret(data url.Values, secret string) (sign string) {
data.Set("secret", secret)
defer data.Del("secret")
keys := make([]string, 0)
for k := range data {
if k == "sign" {
continue
}
keys = append(keys, k)
}
sort.Strings(keys)
str := ""
for _, k := range keys {
str += fmt.Sprintf("%s=%s", k, data.Get(k))
}
fmt.Println("str:", str)
fmt.Println("md5Str:", StringMd5(str))
return StringMd5(str)
}
func StringMd5(str string) string {
hash := md5.New()
hash.Write([]byte(str))
return hex.EncodeToString(hash.Sum(nil))
}
mandarin 框架示例
func (p *pay) TestSign(ctx http.IHttpContext) {
//TODO:更新为自己的req与gameId
var req *payCallbackReq
gameId := "yyds"
_ = ctx.DecodeData(&req)
if req == nil {
ctx.JSON(200, map[string]any{
"errcode": -1,
"errmsg": "参数错误",
})
return
}
if gameId != req.GameId {
ctx.JSON(200, map[string]any{
"errcode": -1,
"errmsg": "参数错误",
})
return
}
rawData, err := ctx.GetRawData()
if err != nil {
ctx.JSON(200, map[string]any{
"errcode": -1,
"errmsg": err.Error(),
})
return
}
content := utils.MD5(rawData)
ps := map[string]any{
"gameId": req.GameId,
"timestamp": req.Timestamp,
"content": content,
"sign": req.Sign,
}
params := bon.O2B(ps).AsDocument()
if req.Sign != p.platform.sign(params) {
ctx.JSON(200, map[string]any{
"errcode": -1,
"errmsg": "签名错误",
})
return
}
//DONE
}