In WeChat, when using Alipay to pay online, you need to jump to the system browser, the solution to the lost user login status
1. The existing implementation, an interface, is to obtain Alipay’s payment link in WeChat (requires login), and there is a callback interface (requires a signature), and a query interface (requires login). Now that payment online payment can only be made in the system browser, the query interface needs to be set to visitor accessible. In order to ensure security, it is decided to do a signature authentication
2. In the interface for obtaining the payment link, the following is realized
<?php
namespace api\helpers;
class AlipayQuerySignerHelper
{
/**
* 获取签名
*
* @param array $data 待签名数据(键值对)
* @param string $secret 签名密钥
* @return string 返回签名字符串
*/
public static function sign(array $data, string $secret): string
{
// 确保按 key 升序排列,签名一致
ksort($data);
// 拼接成 key=value&key2=value2 的格式
$queryString = http_build_query($data, '', '&', PHP_QUERY_RFC3986);
// 生成签名
return hash_hmac('sha256', $queryString, $secret);
}
/**
* 验证签名
*
* @param array $data 待验证的数据(必须包含 query_sign 字段)
* @param string $secret 签名密钥
* @param int $timeout 签名超时时间(默认 600 秒)
* @return bool
*/
public static function verify(array $data, string $secret, int $timeout = 6000): bool
{
if (!isset($data['query_sign'], $data['query_timestamp'])) {
return false;
}
// 判断时间是否超出容忍范围(默认 ±5 分钟)
if (abs(time() - $data['query_timestamp']) > $timeout) {
return false;
}
$providedSign = $data['query_sign'];
unset($data['query_sign']);
$expectedSign = self::sign($data, $secret);
return hash_equals($expectedSign, $providedSign);
}
}
$payload = [
'query_order_id' => $order->id,
'query_user_id' => $order->user_id,
'query_timestamp' => time(),
];
$secret = Yii::$app->params['alipayQuerySignatureKey'];
$sign = AlipayQuerySignerHelper::sign($payload, $secret);
$query = array_merge($payload, ['query_sign' => $sign]);
$queryString = http_build_query($query);
$returnUrl = Yii::$app->params['frontendDomainHttps'] . '/convention/#/pages/ticket_payment_result/ticket_payment_result?convention_id=' . $ticketOrder->convention_id . '&ticket_id=' . $ticketOrder->id . '&_version=2&' . $queryString;
3. In the query interface as follows, the interface responds, as shown in Figure 1
$params = Yii::$app->request->post();
$secret = Yii::$app->params['alipayQuerySignatureKey'];
if (!AlipayQuerySignerHelper::verify($params, $secret)) {
return [
'code' => 10010,
'message' => '签名验证失败',
];
}
// if (strcmp($order->user_id, Yii::$app->user->id) != 0) {
// return [
// 'code' => 10008,
// 'message' => '您没权限进行该操作',
// ];
// }
