[系列] go-gin-api 路由中间件 - 签名验证(七)
目录
上篇文章分享了,路由中间件 - Jaeger 链路追踪(实战篇),文章反响真是出乎意料, 「Go中国」 公众号也转发了,有很多朋友加我好友交流,直呼我大神,其实我哪是什么大神,只不过在本地实践了而已,对于 Go 语言的使用,我还是个新人,在这里感谢大家的厚爱!
这篇文章咱们分享:路由中间件 - 签名验证。
为什么使用签名验证?
这个就不用多说了吧,主要是为了保证接口安全和识别调用方身份,基于这两点,咱们一起设计下签名。
调用方需要申请 App Key 和 App Secret,App Key 用来识别调用方身份,App Secret 用来加密生成签名使用。
当然生成的签名还需要满足以下几点:
- 可变性:每次的签名必须是不一样的。
- 时效性:每次请求的时效性,过期作废。
- 唯一性:每次的签名是唯一的。
- 完整性:能够对传入数据进行验证,防止篡改。
举个例子:
/api?param_1=xxx¶m_2=xxx
,其中 param_1 和 param_2 是两个参数。如果增加了签名验证,需要再传递几个参数:
- ak 表示App Key,用来识别调用方身份。
- ts 表示时间戳,用来验证接口的时效性。
- sn 表示签名加密串,用来验证数据的完整性,防止数据篡改。
sn 是通过 App Secret 和 传递的参数 进行加密的。
最终传递的参数如下:
/api?param_1=xxx¶m_2=xxx&ak=xxx&ts=xxx&sn=xxx
在这要说一个调试技巧,ts 和 sn 参数每次都手动生成太麻烦了,当传递
debug=1
的时候,会返回 ts 和 sn , 具体看下代码就清楚了。这篇文章分享三种实现签名的方式,分别是:MD5 组合加密、AES 对称加密、RSA 非对称加密。
废话不多说,进入主题。
MD5 组合
生成签名
首先,封装一个 Go 的 MD5 方法:
func MD5(str string) string { s := md5.New() s.Write([]byte(str)) return hex.EncodeToString(s.Sum(nil)) }
进行加密:
appKey = "demo" appSecret = "xxx" encryptStr = "param_1=xxx¶m_2=xxx&ak="+appKey+"&ts=xxx" // 自定义验证规则 sn = MD5(appSecret + encryptStr + appSecret)
验证签名
通过传递参数,再次生成签名,如果将传递的签名与生成的签名进行对比。
相同,表示签名验证成功。
不同,表示签名验证失败。
中间件 - 代码实现
var AppSecret string // MD5 组合加密 func SetUp() gin.HandlerFunc { return func(c *gin.Context) { utilGin := util.Gin{Ctx: c} sign, err := verifySign(c) if sign != nil { utilGin.Response(-1, "Debug Sign", sign) c.Abort() return } if err != nil { utilGin.Response(-1, err.Error(), sign) c.Abort() return } c.Next() } } // 验证签名 func verifySign(c *gin.Context) (map[string]string, error) { _ = c.Request.ParseForm() req := c.Request.Form debug := strings.Join(c.Request.Form["debug"], "") ak := strings.Join(c.Request.Form["ak"], "") sn := strings.Join(c.Request.Form["sn"], "") ts := strings.Join(c.Request.Form["ts"], "") // 验证来源 value, ok := config.ApiAuthConfig[ak] if ok { AppSecret = value["md5"] } else { return nil, errors.New("ak Error") } if debug == "1" { currentUnix := util.GetCurrentUnix() req.Set("ts", strconv.FormatInt(currentUnix,