- 探讨一下商圈会员待积分状态查询接口存在的意义
这个接口的文档链接在这里:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_6_7.shtml,是八月新增的几个接口之一。在智慧商圈上线的时候就咨询过一个问题,能不能实现类似某宝的纯自动积分,不需要用户干预,当时提到的说是可能存在非商圈交易无法确认,所以需要用户自己到商圈插件中自己点击一下。 现在官方推出了『商圈会员待积分状态查询』接口,查询到有待提交积分交易后前端可以引导用户进入插件去点击提交。我的疑惑在于,既然可以引导用户去做一个『打开插件->点击』这样的动作,为什么平台方不能自己自动完成这个动作,必须要用户自己去多此一举呢?如果是为了避免非商圈交易积分,那如果用户在商圈内积分后未提交,等到离开商圈1小时后再提交,平台是怎么判断的呢?
2022-08-31 - 消费者投诉2.0推送消息接入企业微信群
微信支付用户如果对订单有疑问或异议,可以通过支付凭证发起投诉,商户需在限定时限内进行回复处理。这个机制设计初衷应该是为了保护消费者权益,促进商户提升服务质量,官方也推出了投诉处理指南。 但是…重点来了,看一下这个苦主记录一次令人糟心的微信支付投诉处理,实际上我们自己也遇到过类似的场景,在商户本身没有任何过错的情况下,用户涉嫌装无辜连续甚至恶意投诉的时候,商户本身除了退款之外几乎没有其他任何维护自身利益的手段。 微信支付在接到用户投诉的时候可以通过回调消息通知商户进行跟进处理,前面描述的这个场景其实跟本文没有直接关系,只是说明接入投诉消息回调的必要性,避免非商户自身意愿导致商家服务质量指标下降。 首先,调用创建投诉通知回调地址接口,向微信支付登记用于处理投诉通知回调的接口url。代码如下(以微信支付API Python SDK为例) [代码]from wechatpayv3 import WeChatPay, WeChatPayType APPID = 'wx1234567890' # 应用appid MCHID = '1234567890' # 微信支付商户号 APIV3_KEY = '1234567890ABCDEFG' # 微信支付APIV3 KEY CERT_SERIAL_NO = '1234567890ABCDEFG' # 商户证书序列号 with open('path_to_private_key/apiclient_key.pem') as f: PRIVATE_KEY = f.read() CERT_DIR = './cert' # 平台证书缓存目录 wxpay = WeChatPay( wechatpay_type=WeChatPayType.MINIPROG, mchid=MCHID, private_key=PRIVATE_KEY, cert_serial_no=CERT_SERIAL_NO, apiv3_key=APIV3_KEY, appid=APPID, notify_url='', cert_dir=CERT_DIR) code, message = wxpay.complaint_notification_create('https://xxx.com/complaint/notify') print('{}, {}'.format(code, message)) [代码] 调用成功的话,微信支付服务器会返回 [代码]{ "mchid": "1234567890", "url": "https://xxx.com/complaint/notify" } [代码] 当发生用户投诉的时候,微信支付会将相关投诉信息推送到前面设置的https://xxx.com/complaint/notify这个地址。 下面将回调消息解密,并将解密后的内容推送到企业微信群里,以便相关人员及时更进处理。 [代码]import json import requests from flask import jsonify, request from wechatpayv3 import WeChatPay, WeChatPayType QIYE_WX_HOOK_URL = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=12345678-abcd-abcd-abcd-12345678' # 企业微信群机器人HOOK URL @app.route("/complaint/notify", methods=['POST']) def wxnotify(): try: wxpay = WeChatPay( wechatpay_type=WeChatPayType.MINIPROG, mchid=MCHID, private_key=PRIVATE_KEY, cert_serial_no=CERT_SERIAL_NO, apiv3_key=APIV3_KEY, appid=APPID, notify_url='', cert_dir=CERT_DIR) result = wxpay.callback(request.headers, request.data.decode()) if result and result.get('resource'): data = result.get('resource') complaint_id = data.get('complaint_id') action_type = data.get('action_type') message = '微信支付用户投诉,投诉单号:{},事件类型:{}。'.format(complaint_id, action_type) data = { "msgtype": "markdown", "markdown": { "content": message } } requests.post(QIYE_WX_HOOK_URL, json=data) return jsonify({"code": "SUCCESS","message": "成功"}) except Exception as e: sslogger.exception('exception in complaint wxnotify: %s' % e) return '', 500 [代码] 至此,调试通过后,只需将涉及到微信支付用户投诉的人员,比如:客服、售后、财务、物流等拉个企业微信群,在微信支付端收到用户投诉或者投诉状态变更时,企业微信群机器人将会自动将提示信息推送到群里,方便了日常更进,也提升了用户体验。 这里只是展示了一个相对简单的业务场景,如果商户的业务量较大,业务系统体系和架构复杂,完全可以利用微信支付提供的消费者投诉2.0接口将用户投诉全流程和自己的业务系统对接,不用跳转到第三方系统即可完成用户投诉的处理回复和结单。
2021-11-24 - 2021-08-14
- 微信支付v3版几个重难点(签名、验签、加密、解密)的python实现
背景介绍 v3版微信支付通过商户证书和平台证书加强了安全性,也大幅提高了开发难度,python版sdk包wechatpayv3内部封装了安全性相关的签名、验签、加密和解密工作,降低了开发难度。下面几个特性的实现,更方便了开发者。 平台证书自动更新,无需开发者关注平台证书有效性,无需手动下载更新; 支持本地缓存平台证书,初始化时指定平台证书保存目录即可。 敏感信息直接传入明文参数,SDK内部自动加密,无需手动处理。 在这里将sdk内部几个涉及到安全性的方法单独抽出来结合官方文档对照一下,方便大家更直观的理解,有兴趣探究sdk内部实现细节的同学可以了解一下,一般应用的无需关注,直接调用sdk包即可。 构造签名信息 对应v3版微信支付api文档的签名生成部分。 [代码]def build_authorization(path, method, mchid, serial_no, mch_private_key, data=None, nonce_str=None): timeStamp = str(int(time.time())) nonce_str = nonce_str or ''.join(str(uuid.uuid4()).split('-')).upper() body = json.dumps(data) if data else '' sign_str = '%s\n%s\n%s\n%s\n%s\n' % (method, path, timeStamp, nonce_str, body) signature = rsa_sign(private_key=mch_private_key, sign_str=sign_str) authorization = 'WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",signature="%s",timestamp="%s",serial_no="%s"' % (mchid, nonce_str, signature, timeStamp, serial_no) return authorization [代码] 验证签名 对应v3版微信支付api文档的签名验证部分。 [代码]def rsa_verify(timestamp, nonce, body, signature, certificate): sign_str = '%s\n%s\n%s\n' % (timestamp, nonce, body) public_key = certificate.public_key() message = sign_str.encode('UTF-8') signature = b64decode(signature) try: public_key.verify(signature, sign_str.encode('UTF-8'), PKCS1v15(), SHA256()) except InvalidSignature: return False return True [代码] 回调信息解密 对应v3版微信支付api文档的证书和回调报文解密部分。 [代码]def aes_decrypt(nonce, ciphertext, associated_data, apiv3_key): key_bytes = apiv3_key.encode('UTF-8') nonce_bytes = nonce.encode('UTF-8') associated_data_bytes = associated_data.encode('UTF-8') data = b64decode(ciphertext) aesgcm = AESGCM(key=key_bytes) try: result = aesgcm.decrypt(nonce=nonce_bytes, data=data, associated_data=associated_data_bytes).decode('UTF-8') except InvalidTag: result = None return result [代码] 敏感信息加密 对应v3版微信支付api文档的敏感信息加解密的加密部分。 [代码]def rsa_encrypt(text, certificate): data = text.encode('UTF-8') public_key = certificate.public_key() cipherbyte = public_key.encrypt( plaintext=data, padding=OAEP(mgf=MGF1(algorithm=SHA1()), algorithm=SHA1(), label=None) ) return b64encode(cipherbyte).decode('UTF-8') [代码] 敏感信息解密 对应v3版微信支付api文档的敏感信息加解密的解密部分。 [代码]def rsa_decrypt(ciphertext, private_key): data = private_key.decrypt(ciphertext=b64decode(ciphertext), padding=OAEP(mgf=MGF1(algorithm=SHA1), algorithm=SHA1)) result = data.decode('UTF-8') return result [代码] 注意事项 以上涉及到的几项签名如果计划抽出来单独使用,需要引入cryptography包。
2021-07-30