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只有我俩自己知道,否则就是他人请求的,给与拒绝
 get_sign.py 加密函数
#!/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)
View Code

requests_server.py,启动一个服务端进行验签

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)
View Code
requests_lient.py 接口请求客户端
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)))
View Code

 

 通过时间戳+key加密验证:

#!/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)
View Code

 

 

 

 

 

相关连接:

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编辑  收藏  举报

导航