微信支付是时下最流行的交易支付方法之一,潜移默化推动着无现今社会的变革。小程序作为微信上的轻应用,同时也开放微信支付的接口,可以通过转账,扫二维码支付。要完成一次具体的订单支付需要完整的支付流程。
第一步:微信小程序调用登录接口获取code,向后台请求openID
1.小程序调用wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
2.开发者服务器以code换取 用户唯一标识openid 和 会话密钥session_key。
getToken: function () {
//调用登录接口
wx.login({
success: function (res) {
var code = res.code;
wx.request({
url: 商户服务器接口地址,
data: {
code: code
},
method: 'POST',
success: function (res) {
wx.setStorageSync('token', res.data.token); //存在小程序缓存中
},
fail: function (res) {
console.log(res.data);
}
})
}
})
}
调用这几行代码就可以向跟微信服务器要code,并且将code传到商户服务器中,记住这里最好使用post发送请求,安全性的东西我应该不用讲了,因为避免其他人滥用接口,于是我们使用token来进行验证。并将商户服务器返回的token存在小程序缓存中。
那么服务器端应该怎么做呢?
我门通过小程序提交的code,和小程序的APPID以及APPSECRET和拼接下列的url,并用curl进行get请求。
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
返回的数据是一个json对象,我门通过使用json_decode(JSON,true)解析为数组,数据包括用户的openID以及session_key,获取到了后我们应该将openID存入数据库中,它代表着用户的身份,那么令牌应该怎么生成呢。
二.token的生成以及缓存
我们根据一个用户表将id和openid联系起来,对应openID的id则是用户的uid,我们可以这么封装
//要缓存的数据数组
$cacheValue = $result; //包含openID和session_key
$cacheValue['uid'] =$uid; //用户id
$cacheValue['scope'] =ScopeEnum::User; //用户权限级别
缓存的方式我们可以选择redis,memcache, 文件缓存等等,采用键值对(key-value)的方式进行存储,记得设置好过期时间。这里的key我们用token来赋值,token可以通过这样的方式进行生成:
//获取32位随机字符串
$str = getRandChar(32); //自定义方法生成32位随机串
//三组字符串进行md5加密
$timeStamp =$_SERVER['REQUEST_TIME_FLOAT'];
//salt
$salt = config('secure.token_salt'); //随机字符串
//返回token
return md5($str.$timeStamp.$salt);
这种算法基本保障了token的唯一性。因为值是我们获取到的openID和session_key所在的数组,所以需要将数组转成json才能存进去。以后的代码当我们需要openID或者uid等时可以直接通过取缓存的方式来取。
三,调用统一下单接口,获取prepay_id,再次签名
四,小程序获取五个参数后,鉴权调起支付
pay: function () {
var token = wx.getStorageSync('token');
var that = this;
wx.request({
url: baseUrl + '/order',
header: {
token: token
},
data: { //产品的数据
products:
[
{
product_id: 1, count: 1
},
{
product_id: 2, count: 1
}
]
},
method: 'POST',
success: function (res) {
console.log(res.data);
if (res.data.pass) {
wx.setStorageSync('order_id', res.data.order_id);
that.getPreOrder(token, res.data.order_id); //调用getPreOrder
}
else {
console.log('订单未创建成功');
}
}
})
},
getPreOrder: function (token, orderID) {
if (token) {
wx.request({
url: baseUrl + '/pay/pre_order',
method: 'POST',
header: {
token: token
},
data: {
id: orderID
},
success: function (res) {
var preData = res.data;
console.log(preData);
wx.requestPayment({ //请求支付
timeStamp: preData.timeStamp.toString(),
nonceStr: preData.nonceStr,
package: preData.package,
signType: preData.signType,
paySign: preData.paySign,
success: function (res) {
console.log(res.data);
},
fail: function (error) {
console.log(error);
}
})
}
})
}
},
五,支付回调
实际上我们需要重写WxPayNotify类的NotifyProcess方法,这里记得Loader::impor()引入那个入口类。
/**
*
* 回调方法入口,子类可重写该方法
* 注意:
* 1、微信回调超时时间为2s,建议用户使用异步处理流程,确认成功之后立刻回复微信服务器
* 2、微信服务器在调用失败或者接到回包为非确认包的时候,会发起重试,需确保你的回调是可以重入
* @param array $data 回调解释出的参数
* @param string $msg 如果回调处理失败,可以将错误信息输出到该方法
* @return true 回调出来完成不需要继续回调,false回调处理未完成需要继续回调
*/
public function NotifyProcess($data, &$msg)
{
//TODO 用户基础该类之后需要重写该方法,成功的时候返回true,失败返回false
return true;
}
也就是说你需要写个新类继承WxPayNotify,再重写NotifyProcess方法,根据检查 d a t a [ ′ r e s u l t c o d e ′ ] 是 否 为 S U C C E S S 可 以 判 断 成 功 与 否 , 成 功 的 话 你 可 以 根 据 业 务 需 求 写 业 务 逻 辑 , 最 后 r e t u r n t r u e 即 可 。 这 时 候 会 想 , 我 重 写 了 这 个 方 法 后 微 信 怎 么 调 用 呢 , 其 实 这 里 微 信 不 是 要 直 接 调 用 这 个 方 法 , 你 应 该 在 微 信 支 付 回 调 的 方 法 中 实 例 化 这 个 新 类 , 然 后 根 据 获 得 的 对 象 去 调 用 H a n d l e ( ) 方 法 。 data['result_code']是否为SUCCESS可以判断成功与否,成功的话你可以根据业务需求写业务逻辑,最后return true 即可。这时候会想,我重写了这个方法后微信怎么调用呢,其实这里微信不是要直接调用这个方法,你应该在微信支付回调的方法中实例化这个新类,然后根据获得的对象去调用Handle()方法。 data[′resultcode′]是否为SUCCESS可以判断成功与否,成功的话你可以根据业务需求写业务逻辑,最后returntrue即可。这时候会想,我重写了这个方法后微信怎么调用呢,其实这里微信不是要直接调用这个方法,你应该在微信支付回调的方法中实例化这个新类,然后根据获得的对象去调用Handle()方法。obj = new 新类(),$obj->Handle()。