码迷,mamicode.com
首页 > 系统相关 > 详细

HMAC-SHA签名流程

时间:2015-09-24 17:44:48      阅读:639      评论:0      收藏:0      [点我收藏+]

标签:

以腾讯上传用户在应用中的等级相关信息为例。接口详情在此【"http://wiki.open.qq.com/wiki/v3/user/get_info"】

在set_achievement这个接口中,接口参数包括openid, openkey, appid, pf, sig, user_attr, format

此接口最后的请求示例为

http://openapi.tencentyun.com/v3/user/set_achievement?
openid=B624064BA065E01CB73F835017FE96FA&
openkey=5F154D7D2751AEDC8527269006F290F70297B7E54667536C&
appid=2&
pf=qzone&
format=json&
user_attr=%7B%22level%22%3A10%7D&
sig=9999b41ad0b688530bb1b21c5957391c

这里除了sig其他参数都只是经过了URL编码而已,所以本文的重点也在如何生成sig。

点我查看详细签名规则

在写代码的过程中我们也可以思考下为什么需要生成签名~

Step 1. 构造源串

第1步:将请求的URI路径进行URL编码(URI不含host,URI示例:/v3/user/get_info)。请开发者关注: URL编码注意事项 ,否则容易导致后面签名不能通过验证。

第2步:将除“sig”外的所有参数按key进行字典升序排列。 注:除非OpenAPI文档中特别标注了某参数不参与签名,否则除sig外的所有参数都要参与签名

第3步:将第2步中排序后的参数(key=value)用&拼接起来,并进行URL编码。请开发者关注: URL编码注意事项 ,否则容易导致后面签名不能通过验证。 第4步:将HTTP请求方式(GET或者POST)以及第1步和第3步中的字符串用&拼接起来。

Step 2. 构造密钥

得到密钥的方式:在应用的appkey末尾加上一个字节的“&”,即appkey&

Step 3. 生成签名

1. 使用HMAC-SHA1加密算法,使用Step2中得到的密钥对Step1中得到的源串加密。 (注:一般程序语言中会内置HMAC-SHA1加密算法的函数,例如PHP5.1.2之后的版本可直接调用hash_hmac函数。)

2. 然后将加密后的字符串经过Base64编码。 (注:一般程序语言中会内置Base64编码函数,例如PHP中可直接调用 base64_encode() 函数。)

3. 得到的签名值结果如下:

FdJkiDYwMj5Aj1UG2RUPc83iokk=

以下是生成sig的解决方案:

def getSig(cfg):
	strFilter = ".-_"
	codeUrlAddr = urllib2.quote(cfg[‘urlAddr‘],strFilter)  
	urlData2 = sorted(cfg[‘urlData‘].iteritems(), key=lambda d:d[0])
	codeStr0 = ""
	for (value01,value02) in urlData2:
		if codeStr0:
			codeStr0 += "&" + str(value01) + ‘=‘ + str(value02)
		else:
			codeStr0 += str(value01) + ‘=‘ + str(value02)
	codeStr1 = urllib2.quote(codeStr0)	 
	codeConn = cfg[‘urlMethod‘] + ‘&‘ + codeUrlAddr + ‘&‘ + codeStr1
	sig = hmac.new(cfg[‘appkey‘] + ‘&‘, codeConn, hashlib.sha1).digest().encode(‘base64‘).rstrip()
	return sig

def test(): 
	urlData = {
		‘openid‘ : ‘12345‘,
		‘openkey‘ : ‘12345‘,
		‘pf‘ : ‘wanba_ts‘,
		‘appid‘ : 12345,
		‘format‘ : ‘json‘,
		‘user_attr‘ : ‘{"level":%d}‘ % 1234
	}
	urlcfg = {
		‘urlAddr‘ : ‘/v3/user/set_achievement‘,
		‘urlMethod‘ : ‘GET‘,
		‘appkey‘ : ‘ABCDWFSFFG‘,
		‘urlData‘ : urlData
	} 
	urlData[‘sig‘] = getSig(urlcfg)
 

第一步:将请求的URI路径进行URL编码(URI不含host,URI示例:/v3/user/get_info)。

urlCfg中urlAddr是第一步中的请求的URI路径。

URL编码规则:

签名验证时,要求对字符串中除了“-”、“_”、“.”之外的所有非字母数字字符都替换成百分号(%)后跟两位十六进制数。

十六进制数中字母必须为大写。

strFilter = ".-_" #不需要替换的字符
codeUrlAddr = urllib2.quote(cfg[‘urlAddr‘],strFilter)# url编码

第二步:将除“sig”外的所有参数按key进行字典升序排列。

urlData中就是第二步要求的sig参数外的所有参数,采用sorted方式进行排序。

urlData2 = sorted(cfg[‘urlData‘].iteritems(), key=lambda d:d[0])

第三步:将第2步中排序后的参数(key=value)用&拼接起来,并进行URL编码。

codeStr0 = ""
    for (value01,value02) in urlData2:
        if codeStr0:
            codeStr0 += "&" + str(value01) + ‘=‘ + str(value02)
        else:
            codeStr0 += str(value01) + ‘=‘ + str(value02)
    codeStr1 = urllib2.quote(codeStr0)

当我看到urllib.urlencode可以用来直接生成&进行拼接的时候非常开心,但是后来发现它会对value进行url编码。这与我们的要求是不符合的。所以采用了上面这种诡异的方式。

第四步:将HTTP请求方式(GET或者POST)以及第1步和第3步中的字符串用&拼接起来。

codeConn = cfg[‘urlMethod‘] + ‘&‘ + codeUrlAddr + ‘&‘ + codeStr1

Step2和Step3

sig = hmac.new(cfg[‘appkey‘] + ‘&‘, codeConn, hashlib.sha1).digest().encode(‘base64‘).rstrip()

这样就得到了sig的值,文档看起来有些复杂,但是一步步做下来其实难度也不大。

接下来就是按照文档要求进行数据请求啦~

urlStr1 = urllib.urlencode(urlData)
 url = urlHost + qqUserInfos[‘getPlayzoneUserInfoUrl‘] + ‘?‘ + urlStr1
    
 request = urllib2.Request(url)
 result = json.loads(urllib2.urlopen(request).read())

在这个过程中不知道有没有小伙伴好奇为什么我的urlData里面的user_attr要像下面这样写

‘user_attr‘ : ‘{"level":%d}‘ % 1234

其实刚开始我是直接把{"level:1234}这个字典赋值给user_attr的。但是在操作的过程中发现由于python会把双引号自动变成单引号,导致生成的签名一直有问题。所以采用json格式来解决这个问题。

你以为本文这就完了?当!然!不!是!还有刚开始提出的问题没回答捏~

sooooo...为什么要生成签名

The answer is "为了确定数据来源正确合法"

双方如何根据签名确定数据来源正确,以腾讯为例:

1.腾讯给我们一个appkey用作密钥,我们按照腾讯约定的签名方式对sig以外的参数进行签名

2.生成签名后,将用作签名的参数和签名一起传给腾讯服务器。

3.服务器将签名与我们的appid对应的appkey进行解密。

4.将传递过去的参数排序,然后与生成的参数进行对比。若数据一致则能保证数据真实。

HMAC-SHA签名流程

标签:

原文地址:http://www.cnblogs.com/JAYIT/p/4835954.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!