python对接口sign签名操作
描述
一般公司对外的接口都会用到sign签名,对不同的客户提供不同的apikey ,这样可以提高接口请求的安全性,避免被人抓包后乱请求。
sign签名是一种很常见的方式
#!/usr/bin/env python # -*- coding:utf-8 -*- import urllib.parse import hashlib import requests import json #_______________________签名方式一___________________________________________________ def sign_body(body, apikey): '''请求body sign签名''' # 列表生成式,生成key=value格式 a = ["".join(i) for i in body.items() if i[1] and i[0] != "sign"] # print(a) # 参数名ASCII码从小到大排序 strA = "".join(sorted(a)) # 在strA后面拼接上apiKey得到striSignTemp字符串 striSignTemp = strA+apikey # MD5加密 def jiamimd5(src): m = hashlib.md5() m.update(src.encode('UTF-8')) return m.hexdigest() sign = jiamimd5(striSignTemp.lower()) # 得到sign签名后新的body值 body["sign"] = sign return body if __name__ == '__main__': apikey = "12345678" # 验证密钥,由开发提供 body = { "username": "test", "password": "123456", "mail": "", "sign": "" } print(sign_body(body, apikey=apikey)) ##_____________________________签名方式二___________________________________ def _getSign(params, key): change = ksort(params) encode_param = urllib.parse.urlencode(change) decode_param = urllib.parse.unquote_plus(encode_param) encode_str = decode_param + key m = hashlib.md5() m.update(encode_str.encode('utf-8')) sign = m.hexdigest() return sign def ksort(d): return [(k,d[k]) for k in sorted(d.keys())] if __name__ == '__main__': key='288jieu439ji2hik48je3jlo9806hw1' body = { "username": "test", "password": "123456" } body['sign']=_getSign(body,key) print(body)
实际案例1:
#!/usr/bin/env python # -*- coding: utf-8 -*- import urllib.parse import hashlib import requests import json #_____________________________________________客户端提交________________________________________________ def _getSign(params, key): '''数据加密处理''' change = ksort(params) encode_param = urllib.parse.urlencode(change) decode_param = urllib.parse.unquote_plus(encode_param) encode_str = decode_param + key m = hashlib.md5() m.update(encode_str.encode('utf-8')) sign = m.hexdigest() return sign def ksort(d): '''遍历字典转成list''' return [(k,d[k]) for k in sorted(d.keys())] def get_address(name,time): data = { "_name": name, "_time": time } key='288jieu439ji2hik48je3jlo9806hw1' #开发提供的key data['sign']=_getSign(data,key)#调用签名函数,并追加到data print('提交请求数据:',data) r=requests.post('http://127.0.0.1:8000/addes',params=data) _json=json.loads(r.text) print(_json) if __name__ == '__main__': get_address('李小龙', 1523803489) #__________________________________________服务端验证sign_______________________________________________ ''' 判断sign是否与客户端一致即可 ''' def _getSign(params, key): del params['sign']#把sign删除了在加密验证 change = [(k,params[k]) for k in sorted(params.keys())] encode_param = urllib.parse.urlencode(change) decode_param = urllib.parse.unquote_plus(encode_param) encode_str = decode_param + key #print(encode_str)#把所有提交的数据及key拼接加密 m = hashlib.md5() m.update(encode_str.encode('utf-8')) sign = m.hexdigest() return sign if __name__ == '__main__': bb={'_time': 1523803489, '_name': '李小龙', 'sign': '9e25aff882368aebc175316ee53b8f38'}#这里是客服端提交的数据 key='288jieu439ji2hik48je3jlo9806hw1' print(_getSign(bb,key))
实际案例2:
为什么要签名?
1、防止接口被恶意调用,增加服务器的压力
2、保证数据的一致性(即发送和收的的数据相同)
签名校验原理?
1、简单点的理解就是客户端发送{"username":"jack","password":"aaa123456"}给服务端,通过一个key="hello world"加入到你的请求体里面,然后通过一系列方式得到一个sign,你的发送数据变成{"username":"jack","password":"aaa123456","sign":"DKAG663F"}
2、服务端得到数据之后,去除sign字段,得到客户端需要发送的真实请求数据,然后用相同的key="hello world",用相同的手段对其进行加密,同样得到一个new_sign,如果sign==new_sign,那证明是自己人请求的,数据也没用被修改,因为key只有我俩自己知道,否则就是他人请求的,给与拒绝
1、防止接口被恶意调用,增加服务器的压力
2、保证数据的一致性(即发送和收的的数据相同)
签名校验原理?
1、简单点的理解就是客户端发送{"username":"jack","password":"aaa123456"}给服务端,通过一个key="hello world"加入到你的请求体里面,然后通过一系列方式得到一个sign,你的发送数据变成{"username":"jack","password":"aaa123456","sign":"DKAG663F"}
2、服务端得到数据之后,去除sign字段,得到客户端需要发送的真实请求数据,然后用相同的key="hello world",用相同的手段对其进行加密,同样得到一个new_sign,如果sign==new_sign,那证明是自己人请求的,数据也没用被修改,因为key只有我俩自己知道,否则就是他人请求的,给与拒绝
get_sign.py 加密函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/usr/bin/env python # -*- coding:utf-8 -*w ###____________________________________________加密算法___________________________________________________ import hashlib # 导入模块hashlib # md5加密算法 def MD5(str): ''' :param str: 需要加密的字符串 :return: 加密完成的密文 ''' md = hashlib.md5() # 创建md5对象 md.update(str.encode(encoding='utf-8')) return md.hexdigest() # 获取sign签名 def get_sign(map: dict, key: str): ''' :param map: 接口的请求数据 :param key: 客户端与服务端约定的key :return: 签名 ''' # 遍历字典,组成特定格式(k1=v1&)字符串的列表 li = [(k, map[k]) for k in sorted(map.keys())] result = "" for i in li: result += i[0] + "=" + i[1] + "&" # print(result) result=password=aaa123456&username=jack& result_new = result + 'key=' + key # print(result_new)result_new=password=aaa123456&username=jack&key=hello # md5加密,并转为大写。 sign = MD5(result_new).upper() # 返回sign return sign #95E34CB05C944D33DE166E03942C83B3 if __name__ == '__main__': body={"username":"jack","password":"aaa123456"} key="hello"#约定的key sign=get_sign(body,key) print(sign)
requests_server.py,启动一个服务端进行验签
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from flask import Flask, request import json from flask_cors import CORS from sign_test.get_sign import get_sign app = Flask(__name__) # 允许跨域 CORS(app, resources=r'*') @app.route('/api', methods=['POST']) def api(): data = json.loads(request.data) print("请求体的数据:{}".format(data)) sign = data["sign"] del data["sign"] # 将请求的数据去除sign之后,用相同的key去加密,得到一个new_sign new_sign = get_sign(data, key="hello") print("服务端的签名:{}".format(new_sign)) # 判断客户端发过来的签名是否与服务端的签名一致 if sign == new_sign: '''do something 、、、 、、、 ''' res = {"status": 200, } return json.dumps(res) else: return json.dumps({"status": 500}) if __name__ == '__main__': app.run(host='localhost', port=8009, debug=True)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from sign_test.get_sign import get_sign import requests, json # 主程序 if __name__ == "__main__": # 加密秘钥 key = "hello"#key是双方约定的,我这边就是直接写死一个,与服务端一直 body = {"username": "alex", "pwd": "123456"} sign = get_sign(body, key) body["sign"] = sign url="http://localhost:8009/api" res = requests.post(url=url, data=json.dumps(body)) print("请求体body={}".format(body)) print("返回值:{}".format(json.loads(res.content)))
通过时间戳+key加密验证:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/usr/bin/env python # -*- coding:utf-8 -*- import hashlib import time #_______________________________________________________通过密钥+时间戳的方式加密验证接口_____________________________ def validate_sign(sign, salt,kwargs): """时间戳有效期10秒,排序顺序为:盐+时间戳+按照字母排序的参数的值""" print('传入时间',kwargs["time"]) # 首先判断ts时间戳,有没有超过10秒有效期 now_ts = int(time.time()) print('当前时间',now_ts) #time.sleep(12) if now_ts - kwargs["time"] > 10: return False # 对字典中的键进行排序 sort_dict = sorted(kwargs.items(), key=lambda x: x[0]) # 按照排序拿出值,拼接成字符串,然后加密生成签名 s = salt + str(kwargs["time"]) for key, value in sort_dict: s += str(value) # 使用sha256加密,与app也要约定好加密方式 new_sign = hashlib.sha256(s.encode('utf-8')).hexdigest() if sign !=0: print('原来的sign:',sign) print('新的sign:', new_sign) # 比对签名是否一致 if sign == new_sign: return True return False else: return new_sign if __name__ == '__main__': salt_key = 'nx24Tej@R4gWVCopJkjHWjBo@n58LdQ5' # 盐, 加密生成签名的秘钥 dict={"phone":"15555555555", "password":"123456","time":int(time.time())} #客户端签名(0表示客户端) name1 = validate_sign(0,salt_key,dict ) print('客户端签名:',name1) #服务端签名验证 name=validate_sign(name1, salt_key,dict) print('服务端签名:',name)
相关连接:
https://www.cnblogs.com/-wenli/p/14016905.html ............................................Flask实现token生成及验证
https://www.cnblogs.com/crowbrother/p/16217540.html ..................................python实现支付接口的sign签名
https://blog.csdn.net/w1054230914/article/details/128872847 .........................接口签名描述
posted on 2020-08-26 20:52 chen_2987 阅读(1704) 评论(0) 编辑 收藏 举报