1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 支付宝签名与验签 return_url和通知页notify_url

支付宝签名与验签 return_url和通知页notify_url

时间:2023-12-19 23:31:40

相关推荐

支付宝签名与验签 return_url和通知页notify_url

1 支付宝签名与验签

签名与验签的作用

首先了解下使用RSA签名与验签的作用是什么?

对数据进行签名后,可以保证数据完整性,机密性和发送方角色的不可抵赖性,可以有效防止请求信息信息被篡改。

以商户服务端(A)、支付宝服务端(B)、发送的消息内容(C)、加密后的签名(D)举例如下:

• 签名:商户A将需要发给支付宝B的消息内容C利用app私钥进行加密得到签名D。然后A将C和D一起发给B。

• 验签:支付宝B接收到内容C和签名D后,使用app公钥进行验证,验证签名D解密后的内容是否与内容C相同,相同返回true验签成功。反之,返回false验签失败。

以上是商户端的加密流程,支付宝端签名和验签流程是刚好与之相反,支付宝端签名,商户端验签。所以在整个接口请求过程中一共用到了两对密钥,商户端的应用密钥和支付宝端的支付宝密钥。深入了解可参考上期提到的《密钥交互原理》。

1.1 商户服务器签名

商户服务器生成支付页面API url请求参数,这些参数需要使用app应用私钥加密,而支付宝收到数据后,使用app应用公钥解密后与原始请求参数对比,以确定确实是商户服务器发送的请求。

1.2 商户服务器端自行实现签名过程

过程: 筛选请求参数并排序==>拼接==>使用app应用私钥加密==>拼接成url

(然后使用该url向支付宝发起请求,支付宝返回支付页面)

准备的参数如下:

REQUEST URL: /gateway.doREQUEST METHOD: GETCONTENT:app_id=101800718925method=alipay.trade.page.paycharset=utf-8sign_type=RSA2timestamp=-10-13 09:58:50version=1.0biz_content={"out_trade_no":"051981561010099","product_code":"FAST_INSTANT_TRADE_PAY","total_amount":88.88,"subject":"Iphone6 16G","body":"Iphone6 16G"}return_url=""notify_url="/notify"

1、筛选

获取所有需要发送给支付宝的请求参数(详见API的参数需求说明),不包括字节类型参数,如文件、字节流,剔除 sign 字段,剔除值为空的参数。

请求参数筛选之后形式如下:

app_id=101800718925method=alipay.trade.page.paycharset=utf-8sign_type=RSA2timestamp=-10-13 09:58:50version=1.0biz_content={"out_trade_no":"051981561010099","product_code":"FAST_INSTANT_TRADE_PAY","total_amount":88.88,"subject":"Iphone6 16G","body":"Iphone6 16G"}return_url=""notify_url="/notify"

2、排序

按照第一个字符的键值 ASCII 码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值 ASCII 码递增排序,以此类推

排序之后形式如下:

app_id=101800718925biz_content={"out_trade_no":"051981561010099","product_code":"FAST_INSTANT_TRADE_PAY","total_amount":88.88,"subject":"Iphone6 16G","body":"Iphone6 16G"}charset=utf-8format=jsonmethod=alipay.trade.page.paynotify_url="/notify"return_url=""sign_type=RSA2timestamp=-10-13 09:58:50version=1.0

3、拼接

将排序后的参数与其对应值,组合成“参数=参数值”的格式,并且把这些参数用 & 字符连接起来,此时生成的字符串为待签名字符串

生成的待签名内容形式如下:

app_id=101800718925&biz_content={"out_trade_no":"051981561010099","product_code":"FAST_INSTANT_TRADE_PAY","total_amount":88.88,"subject":"Iphone6 16G","body":"Iphone6 16G"}&charset=utf-8&format=json&method=alipay.trade.page.pay&notify_url="/notify"&return_url=""sign_type=RSA2&timestamp=-10-13 09:58:50&version=1.0

4、加密

使用各自语言对应的 SHA256WithRSA(对应sign_type为RSA2)或SHA1WithRSA(对应sign_type为RSA)签名函数利用商户私钥对待签名字符串进行签名,并进行 Base64 编码,得出的加密字符串集存储于sign这个参数中

使用app应用私钥加密(必须与应用 ID 中上传的应用公钥是匹配的,支付宝会使用应用公钥解密:即验签),

app应用私钥形式如下:

MIIEpQIBAAKCAQEAv/JKebY7hSXhg1q3V2Z1KCTtfCDLBIhfaLM3RqkHUsxoqdiXYzzJKX7f/hIVdkL/6Gza0PTDbG3dohCx5G2yIo6Gariq4IyFk4cDc3jIooi4kShz4nVzEgS333ZdmZ3LHRcGf2353INUp55Sv0dOMDkLeZA09lJujisJ5UGfgeFM79v+a1tvlcwPnMQmbF9t9ddBhH6/WDZgEL+x2EaytX9+tyhRLffA12OewgI8e0DACk2XSO1vyOtYl5e3LI/DVjByiwzUr+bWpqNKAm4PmzTL5OFvZBE5LwQSJ/qYu6pA2BKuxmn65lsBk/sGBwMJa/WezZIb+BALsyyOKWxVCwIDAQABAoIBAG9FnjcAlXCSjTEAndhk5PXosmOK/yYZiHXBrwGfa0dsiCAuF1TIIDWV/3PiN97e6EttD0yjF8b7ycfxta6eiO3PgczMUQLrc2QamL2P/395ksVTlhppy9NeONmqXIh5GQ48EuA8eOSEncat2XpZc9Iwv54xIwLItp5kBNCKQlWfrNKJUp1ZjpVBfh1fENjktkdyN9uzZp6PInuEH5WM//4tTGi78oGzDtg1r8DwHS5KqXYo9ulEOyd0KH1OAYXZLqjYJ2xIzotlvu7WlWxYFwK5+D+iiYYdF+vrNnXaQQRcwHJztc386usdMnk5FRRZNdoHrcJ2QOpSXvni14vfksECgYEA7KgbZx8oyudulQqzzus/m2hUudbPJbTa6w0P10QX1Efn2mEmWeg6p7bj3L+cN/OoOWZ4Ke0xKxkOQ0WYLLOvNVxRzF0Xjj+C57YHtShvbwe54IZFNrDe/FKHhpBYS6vFzKX6ck3HHEjC2WlqolAEHAbYFGTHobKBa0qgIvPl/UUCgYEAz6KmhQhNTOBIG/kY7MVHLfMQyvefhT+Xm/h73hJK3Nfp1M+QQZIj1uiDld6bEu7vUP91K6+JyE0BJZcP4eHCmzkp2KjcyGDWJQfbpaaH9RT0uiR7D7obBHf8BGOAgnA809SX8CD3cS+gCx8cqiIsMZB494A2iVyNiiufVIX1Zg8CgYEA0jHpzOjnEXkHRgewduuJnl3HSxyY9lOxUa5TUI6hX6HSM6uwJZDXcBlIP8xMU4Ht+7WgqxSKZE4n1eZdZ+7cgteRq6NPhb+xZF7Qb74PY52IIf0AQrhMBe7Dguh4FBXoZIFTdezRGbUio3o3BR1u2PnXOB3fFiZ3PrWUkBbzQsUCgYEApbd5E+AmYd73bmwHOqHRR5kho/yycpTomfFeW0VaPpyM4e6vgcXzmMiGjQzX0+qjUpAwoic93oGnEqtYX73hpiWfgm5zl/HBuFhnM/SPukl5cT9AgLLWcWCZ4Z7QqEqQIbkhcuO82bdbEsVICXmwr/ZQtai83jDiPo7GYZ1w2H0CgYEAjFxeHoUKnMO0GqOHy/v3gqS4357kTz7/PfXqbIO2OvyW5KX9MXeVJ6OD6KiqVGBGStF8Vy8VT/j2KXCjiJQ91gFqEJvkadsB1HXfXxPRwUYi3i7BaadpfnW3cM6uAE6iPVqhGu4Z0uyUp/koGgkBr/qbnwRgF9/hXb8Pygu0s5c=

生成的签名(sign)形式如下:

p0du54PYDnCdHjYFgc0mri5KqA09ziGVJZi/xaDiPzvePlMGGGHcBzH8qNV3pYvBxv60ezxC2a9ZM97bTkmJZt21mb5tBDPWBpYZsJqU3XCMgDnlisiq3Us2glwB9eHzVaZPTW14lSykkPEwLk8mwzQdwM5/SmCnHpAT+I3BOkBUPs6pl5i0eE/dA4ePAkXgWIqmsQbgh9As7Fgh65wScxbzsC8FJfbMhQDNV94WYCQd9cbkyOPidpnT9o7u2GoqkVjm2N73Ja2ObSdp5PQNbQ8UdtJ+PYBUTXDa7cLIkoc00JGSCqhGPA6rFCnNuAay/C4wtSKJzKZ5XpRWwYrkWQ==

5、拼接成url

把生成的签名赋值给 sign 参数,拼接到请求参数中,产生url,形式如下:

/gateway.do?app_id=101800718925&biz_content={"out_trade_no":"051981561010099","product_code":"FAST_INSTANT_TRADE_PAY","total_amount":88.88,"subject":"Iphone6 16G","body":"Iphone6 16G"}&charset=utf-8&format=json&method=alipay.trade.page.pay&notify_url="/notify"&return_url=""sign_type=RSA2&timestamp=-10-1309:58:50&version=1.0&sign=p0du54PYDnCdHjYFgc0mri5KqA09ziGVJZi/xaDiPzvePlMGGGHcBzH8qNV3pYvBxv60ezxC2a9ZM97bTkmJZt21mb5tBDPWBpYZsJqU3XCMgDnlisiq3Us2glwB9eHzVaZPTW14lSykkPEwLk8mwzQdwM5/SmCnHpAT+I3BOkBUPs6pl5i0eE/dA4ePAkXgWIqmsQbgh9As7Fgh65wScxbzsC8FJfbMhQDNV94WYCQd9cbkyOPidpnT9o7u2GoqkVjm2N73Ja2ObSdp5PQNbQ8UdtJ+PYBUTXDa7cLIkoc00JGSCqhGPA6rFCnNuAay/C4wtSKJzKZ5XpRWwYrkWQ==

经过urlencode加密后实际形式如下:

app_id=102400749214&biz_content=%7B%22subject%22%3A%22%5Cu5929%5Cu5929%5Cu751f%5Cu9c9c041010554419%22%2C%22out_trade_no%22%3A%22041010554419%22%2C%22total_amount%22%3A%2233.99%22%2C%22product_code%22%3A%22FAST_INSTANT_TRADE_PAY%22%7D&charset=utf-8&method=alipay.trade.page.pay&notify_url=http%3A%2F%2F120.77.253.68%3A8000%2Fuser%2F&return_url=http%3A%2F%2F120.77.253.68%3A8000%2Fuser%2Forder%2F1&sign_type=RSA2&timestamp=-04-10+10%3A55%3A50&version=1.0&sign=cGeKkdf4tsZ18BvcfwbuclshF6XR9vAZYhGsJk%2BznaxGzl%2FsDPoG28e2ihw%2BS47rEJ64xGfTaT57ids7RckpsvOHseLUi5ziPu6VO38ogFvsrhXRceo2Jtp0TGJqaCAP4Chrpz2SD2j08GjH0RXUiK3I%2FX1IYxfN2lMbZfFi0SHqPv9eSoDVaYzXznYW%2BMcPX5zWfjPNsVXChRKIi8aeMKPjdGztDK9cxdbC7gol07EGRAcpAbNT73WTn7PPKqEnpV8o9vkIZ65L3mmupQmXkqsYoXE%2FlW4Y2P1IsZMg0diZxtQKOoQM5ObkRxFwbq%2BmrPE7uHvG2PEGRHN3S2mzOg%3D%3D

1.3 使用SDK自动签名

自动签名可以很方便的帮助我们实现签名操作。

class OrderPayView(View):'''支付'''def post(self, request):'''支付'''# 用户登录判断user = request.userif not user.is_authenticated():return JsonResponse({'res': 0, 'errmsg': '用户未登录'})# 获取订单idorder_id = request.POST.get('order_id')# 校验参数if not order_id:return JsonResponse({'res': 1, 'errmsg': '无效订单'})try:order = OrderInfo.objects.get(order_id=order_id,user = user,pay_method = 3,order_status = 1,)except OrderInfo.DoesNotExist:return JsonResponse({'res': 2, 'errmsg': '订单错误'})# 调用支付宝API# 初始化支付对象app_private_key_string = open(os.path.join(settings.BASE_DIR, 'apps/order/app_private_key.pem')).read()alipay_public_key_string = open(os.path.join(settings.BASE_DIR, 'apps/order/alipay_public_key.pem')).read()alipay = AliPay(appid="102400749214", # 应用idapp_notify_url=None, # 默认回调urlapp_private_key_string=app_private_key_string,# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,alipay_public_key_string=alipay_public_key_string,sign_type="RSA2", # RSA 或者 RSA2debug=True # 默认False,使用沙箱环境时置为True)# 调用支付APItotal_pay = order.total_price+order.transit_price # Decimal 是不能序列化的,应转换字符串# 电脑网站支付try:# SDK封装的API会自动签名,省去了我们很多的功夫order_string = alipay.api_alipay_trade_page_pay(out_trade_no=order_id, # 订单idtotal_amount=str(total_pay), # 支付总金额subject='天天生鲜%s' % order_id,#return_url="",return_url="http://120.77.253.68:8000/user/order/1", # 可选, 不填则使用默认notify url#notify_url="/notify" # 可选, 不填则使用默认notify urlnotify_url="http://120.77.253.68:8000/user/" # 可选, 不填则使用默认notify url)except Exception as e:print(e)# 返回:提交支付页面urlpay_url = '/gateway.do?' + order_stringprint(order_string)return JsonResponse({'res':3, 'pay_url':pay_url}) # 将支付地址回传给浏览器,从而引导用户跳转到支付页面

2 商户服务器验签

验证是否是支付宝服务器发来的请求。

商户服务器接收到支付宝的请求后,使用支付公钥解密

2.1 自行实现验签

普通公钥模式:

如当面付扫码支付获取二维码的返回内容为:

{"alipay_trade_precreate_response":{"code":"10000","msg":"Success","out_trade_no":"6141161365682511","qr_code":"https:\/\/\/bax03206ug0kulveltqc80a8"},"sign":"VrgnnGgRMNApB1QlNJimiOt5ocGn4a4pbXjdoqjHtnYMWPYGX9AS0ELt8YikVAl6LPfsD7hjSyGWGjwaAYJjzH1MH7B2/T3He0kLezuWHsikao2ktCjTrX0tmUfoMUBCxKGGuDHtmasQi4yAoDk+ux7og1J5tL49yWiiwgaJoBE="}

则待验签字段为:

{"code":"10000","msg":"Success","out_trade_no":"6141161365682511","qr_code":"https:\/\/\/bax03206ug0kulveltqc80a8"}

同时取出签名值 sign:

VrgnnGgRMNApB1QlNJimiOt5ocGn4a4pbXjdoqjHtnYMWPYGX9AS0ELt8YikVAl6LPfsD7hjSyGWGjwaAYJjzH1MH7B2/T3He0kLezuWHsikao2ktCjTrX0tmUfoMUBCxKGGuDHtmasQi4yAoDk+ux7og1J5tL49yWiiwgaJoBE=

调用验签函数:使用各自语言对应的 SHA256WithRSA (对应 sign_type 为 RSA2) 或 SHA1WithRSA (对应 sign_type 为 RSA) 签名验证函数,传入待验签字段、支付宝公钥、签名内容(sign),验签方法(signType)进行验签,根据返回结果判定是否验签通过(其原理:使用支付宝公钥加密待验签字段,并将结果与签名内容比较,如果相等则验签通过,说明请求是支付宝发送过来的)

2.2 使用SDK自动验签

支付宝SDK封装了验签功能,实现了自动验签

示法代码如下(支付宝返回页return_url和通知页notify_url的视图,使用自动验签):

class AlipayView(APIView):def get(self, request):"""处理支付宝的return_url返回"""processed_dict = {}# 1. 获取GET中参数for key, value in request.GET.items():processed_dict[key] = value# 2. 取出signsign = processed_dict.pop("sign", None)# 3. 生成ALipay对象alipay = AliPay(appid="09190210",app_notify_url="http://115.159.122.64:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True, # 默认False,return_url="http://115.159.122.64:8000/alipay/return/")# 进行验签,确保这是支付宝给我们的verify_re = alipay.verify(processed_dict, sign)# 这里可以不做操作。因为不管发不发return url。notify url都会修改订单状态。if verify_re is True:order_sn = processed_dict.get('out_trade_no', None)trade_no = processed_dict.get('trade_no', None)existed_orders = OrderInfo.objects.filter(order_sn=order_sn)for existed_order in existed_orders:existed_order.trade_no = trade_noexisted_order.pay_time = datetime.now()existed_order.save()response = redirect("/index/#/app/home/member/order")# response.set_cookie("nextPath","pay", max_age=3)return responseelse:response = redirect("index")return responsedef post(self, request):"""处理支付宝的notify_url"""# 1. 先将sign剔除掉processed_dict = {}for key, value in request.POST.items():processed_dict[key] = valuesign = processed_dict.pop("sign", None)# 2. 生成一个Alipay对象alipay = AliPay(appid="09190210",app_notify_url="http://115.159.122.64:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True, # 默认False,return_url="http://115.159.122.64:8000/alipay/return/")# 3. 进行验签,确保这是支付宝给我们的verify_re = alipay.verify(processed_dict, sign)# 如果验签成功if verify_re is True:order_sn = processed_dict.get('out_trade_no', None)trade_no = processed_dict.get('trade_no', None)trade_status = processed_dict.get('trade_status', None)# 查询数据库中存在的订单existed_orders = OrderInfo.objects.filter(order_sn=order_sn)for existed_order in existed_orders:# 订单商品项order_goods = existed_order.goods.all()# 商品销量增加订单中数值for order_good in order_goods:goods = order_good.goodsgoods.sold_num += order_good.goods_numgoods.save()# 更新订单状态,填充支付宝给的交易凭证号。existed_order.pay_status = trade_statusexisted_order.trade_no = trade_noexisted_order.pay_time = datetime.now()existed_order.save()# 将success返回给支付宝,支付宝就不会一直不停的继续发消息了。return Response("success")

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。