看我如何接入腾讯API,以及生成sig签名~\(≧▽≦)/~

以腾讯上传用户在应用中的等级相关信息为例。接口详情在此【"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.将传递过去的参数排序,然后与生成的参数进行对比。若数据一致则能保证数据真实。

看我如何接入腾讯API,以及生成sig签名~\(≧▽≦)/~

上一篇:WinCE平台的程序编译到Win32平台下运行


下一篇:windons C盘应该不够加硬盘的方式