# WeCard 码组件
# 简介
此组件用于集成 wecard 码相关的能力,包括但不限于展示二维码、签约、补缴等。
# 如何使用
# 申请组件
小程序开发者可以在"小程序管理后台-设置-第三方服务-插件管理"中查找插件,并进行申请。在发起申请24小时内,微卡会根据应用的资质进行审核。
# 引入插件
- 在app.json中声明需要使用的插件
{
"plugins": {
"wecard-code-plugin": {
"version": "0.0.7",
"provider": "wx15949dc6d9b035d2"
}
},
}
需指插件的version(当前版本号:0.0.7)和provider(插件提供方:wx15949dc6d9b035d2)
- 在使用的页面的json文件(如index.json)中引用自定义组件
{
"usingComponents": {
"wecard-code": "plugin://wecard-code-plugin/wecard-code"
}
}
# 使用插件
# 1. 安装 wecard-code-sdk
npm install wecard-code-sdk
# 2. 在页面的 js 文件中引入 sdk
引用后在 onLoad
中进行注册
import { wecardInit } from "wecard-code-sdk";
Page({
data: {
userinfo: {},
wecardInitData: false
},
onLoad: function () {
this.wecardInit();
},
wecardInit(e){
wecardInit(this,e);
},
onShow(){
this.getUserInfo();
},
getUserInfo(){
// 获取 userinfo 的接口,并且 setData
}
}
- 在页面上使用组件
<wecard-code
userInfo="{{userinfo}}"
initData="{{wecardInitData}}"
bindInit="wecardInit"
bindLoginStatusExpired="getUserInfo"
>
</wecard-code>
参数 | type | 必填 | 说明 |
---|---|---|---|
userInfo | Object | 是 | 用户信息,参考后文的userinfo的获取说明 |
initData | Object | 是 | 插件初始化信息(直接填写 wecardInitData 即可) |
bindInit | fun(e) | 是 | 直接写 wecardInit 即可,wecard 插件初始化函数 |
bindLoginStatusExpired | fun(e) | 是 | 身份过期后会触发,请重新获取 userinfo 并且 setData 新的 userinfo |
showOpenPayTip | boolean | 否 | 是否展示开通支付功能的提示,默认为 true |
isCaptureScreenEnabled | boolean | 否 | 是否开启截屏功能,默认为 true (表示开启截屏风控,安全性高)。 警告:如果设置为 false,表示关闭截屏风控,安全性大幅降低,建议保持此设置为 true |
# 其他
# 签约组件
另外提供一个发起签约的按钮组件,使用方式如下:
使用前请先在页面上使用 wecard-code-sdk 进行 init 操作,方法同上
在页面级别 json 声明使用签约按钮组件
{
"usingComponents": {
"sign-button": "plugin://wecard-code-plugin/sign-button"
}
}
页面 wxml 声明:
<sign-button
userInfo="{{userinfo}}"
initData="{{wecardInitData}}"
bindInit="wecardInit"
bindSignBack="signBack"
buttonText="开通支付功能"
/>
其中参数如下:
参数 | type | 必填 | 说明 |
---|---|---|---|
userInfo | Object | 是 | 用户信息,参考后文的userinfo的获取说明 |
initData | Object | 是 | 插件初始化信息(直接填写 wecardInitData 即可) |
bindInit | fun(e) | 是 | 直接写 wecardInit 即可,wecard 插件初始化函数 |
bindSignBack | fun(e) | 是 | 获取签约结果 |
buttonText | string | 否 | 按钮文案,默认为“前往开通支付功能” |
在 js 中绑定 function 获取前端签约结果(如果需要保存签约状态,请以服务端为准,不建议保存,微校来维持此状态)
signBack(e){
console.log("[signBack]", e.detail);
// return_code === SUCCESS 为成功
// 更加详细的信息,请查看: https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_14&index=3
const { return_code, return_msg, contract_id } = e.detail;
}
# 小钱包功能页面
# 功能简介
小钱包功能页,可用于用户的福利券、余额、优惠券的展示。
# 使用方式
通过wx.navigateTo
方法跳转,并通过该方法的内置的events
进行事件通信。
事件通信类型:
- 宿主 -> 插件
updateUserInfo
: 传递用户信息
- 插件 -> 宿主
loginStatusExpired
: 登录态过期,通知宿主重新获取身份态
代码示例如下,完整代码可见(pages/wallet/index):
wx.navigateTo({
url: 'plugin://wecard-code-plugin/wallet',
events: {
loginStatusExpired: (data) => {
this.fetchData();
}
},
success: (res) => {
this.walletEventChannel = res.eventChannel;
res.eventChannel.emit('updateUserInfo', this.data.userinfo)
}
})
# request 安全域名添加
若使用了支付功能,请向微卡开发人员咨询需要添加的 request 安全域名
- https://api.unipay.qq.com
- https://midas.weixiao.qq.com
# 用户信息userinfo的获取
1、电子码组件的核心参数是userInfo,这个参数类型为 object,表明了当前 业务侧小程序需要渲染哪个用户的电子码,userInfo的相关属性为:
参数 | type | 必填 | 说明 |
---|---|---|---|
ocode | string | 是 | 电子码侧客服提供的主体编码 |
timestamp | string | 是 | 时间戳,从1970年1月1日00:00:00至今的秒数,即当前时间(北京时间) |
nonce | string | 是 | 随机字符串,长度32字符以下 |
userid | string | 是 | 业务侧定义的用户标识,用来传递至微卡侧 |
openid | string | 否 | 业务侧小程序的openid;非必填;不填时无法使用支付相关功能 |
appid | string | 否 | 业务侧小程序的appid,和openid对应;非必填;不填时无法使用支付相关功能 |
origin | string | 是 | 来源:0 微信 1 企业微信 |
signature | string | 是 | 签名,详情见下一小节userinfo签名算法 |
2、userinfo签名算法
1)准备一对 2048位PKCS#8格式 的RSA公私钥,保存好私钥(切勿放入小程序客户端),并将公钥提交给 微卡侧
2)删选并排序:获取所有请求参数,不包括字节类型参数,如文件、字节流等,剔除signature字段,剔除值为空的参数,并按照第一个字符的键值ASCII码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值ASCII码递增排序,以此类推
3)拼接:将排序后的参数与其对应值,组合成“参数=参数值”的格式,并且把这些参数用&字符连接起来,此时生成的字符串为 待签名字符串
4)签名:使用各自语言的 SHA256WithRSA 签名函数,并利用步骤1中生成的 私钥 对 待签名字符串 进行签名,并进行 BASE64 的编码,得到 signature 值,放入数据包中
3、签名DEMO
PHP:
<?php
//生成的私钥
$privateKey = '-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDN5Ikc1bACyZqA
VxNAxmblHd0CaIi/EVlvp3eqQ82raT//XqbYar/Db7lDoIamwJyK0Hf2mzpisdXP
spuvUOYNuU0TjBN+flC85AFElS3sZhsAolFXQBUk4IEKfD2fRaLPkIs+v4kHmP7z
A4TkTPl2nvWb3YbKokWbomHwUgXFfnEfj/3cKKZQxwXJFx2Lc71a/+zTcpaEIy12
XcMsQxHBSItJA9U9Gw8RQLbH4tAUzzsXlcH0OFF9NQ/CRRJ6Nep6YVyX+BQx/55U
lOJdKo2h1qQz6rmKCOz5rIBqh3rntsYPbJd7meDts8nWEnGaNS5F+PZdG0I2udTJ
nDk/B8SRAgMBAAECggEAaWoC0WKOtT6m/eKXFuj9sXyytRL0QG8PjVz+pYwFdydx
/rtlTRSKjfNbtUYw6ptfCqtlYDtljzZhs+9MSlxvDMO8tK9ZI8BkcfGCvKxsUMaO
OKriXnuO18yiBM5Ldopeq0rkIAJMlDk+/wjkN0c5ygPk2CJ5arHeVaqz3ikAj3Yc
HrYCzmLxVHoX1IvFd0VEp/7EJjcH8ty1RzJWdM++de5vHAAzLGdZCb4dIUnNHGbn
H97fMOTKYx+0K2tVCjNAoRUejsH22tpj9ospKQ0PydyGB0pzTrURx0/A/BWeKScC
2QHM3/puJrQRoZTi+GwVgQXyaPWp6H9pEim7NWGQgQKBgQDslXEy+MVGehnvURvd
2f7BFe6IQeJIrT2jnvn3wRCUw95oQdxp4RIQJWmAtF/bJIqAfSh+NvjsyaCke0iD
K/Si8WNiiEi/yGXvR3DnXXyaVJNXuw21NomlVjDfbfbhJLZ+XuSo3wQDmdK2WadK
521U1D1fITD8m5rWaA1I********gQDeykiHkAPXC9PbxxoxpaArPhlXeAqqJFDS
w8jy9hU+CKdVKmhSd64xnljExH5QpLyD/ER4IAjRRRLQiuh5t8DeZe3KLfRo/Zpd
PaPp/6W0QoiPYlpJ4g8beeffs8ZfFcWrlwslHlKWMmY5NXm/8xrAhJTxrrFRmShp
aS6FzPuwKQKBgAXlH2H2wuujpTvKWJhpkyh6hGwOwDWxY2TNVEsxG1mpm8QbSAO3
YPzYAc38MJtESNM0yyqB8ifsSj1u+PqTwM/ClghhfvaQZsHUlOKe+LjbvKQl/Ax0
5G8jO6qFke5APO/fK3FtxSrVzWNPzpRWOeowM6tIJ3FT60LGavZSLR0pAoGAD+R4
Jgt06qsyUrQyPyZkdZE5d47dm+N5TH+g3wwE2eb+IMokpPVanLmB9Y9av1/w/q1J
KRSH7H2z6OJv0Pb1sCevPcPncnHcyBf0kGWnKWOxoCDQ9gJFN52Ll96YIQJJloLw
zZYLKCGyPxR8ed/aoa8TfOYMShjV1CcnpW3I6nkCgYBAZrMW+1BZs+wP7oFHygYJ
utcWCq4rDTT9SunA4Kk1Lh4LUjK3JgmrJtoJomNNApXIHlte+hC2cRgYLYP/zO1y
4o5lWuOR8/6tmrGGhSmRv8xuYndRQ7Y3NUmXXPHieOrK3sIEJ15Md7wfSF4cjriS
fSXnNxzJYs4gUNG9XNwGvA==
-----END PRIVATE KEY-----
';
//待签名
$params = [
'ocode' => '1563506591',
'timestamp' => '1589720896',
'nonce' => 'demononce',
'userid' => 'baronliu',
'appid' => 'wx15949dc6d9b035d2',
'openid' => 'demoopenid',
'origin' => '0',
];
//排序并拼接
ksort($params);
$signString = rawurldecode(http_build_query($params));
//进行签名
$p = openssl_get_privatekey($privateKey, null);
$sign = '';
openssl_sign($signString, $sign, $p, OPENSSL_ALGO_SHA256);
$sign = base64_encode($sign);
openssl_pkey_free($p);
$params['signature'] = $sign;
//在后端计算好签名后将数据包传递至前端码组件内
var_dump($params);