微信JSSDK提示invalid signature解决

在使用微信JSSDK过程中,发现如果用户从分享链接进入后,会报告jssdk签名错误(invalid signature),

这些URL正常:

1
http://example.com/page1
1
http://example.com/page1?aaa=1&bbb=2

这些URL提示签名错误:

1
http://example.com/page1?sharer_username=gh_f09a8z12&sharer_sharetime=1563663628&scene=0&clicktime=1563768946&from=timeline
1
http://example.com/page1?bbb=2&aaa=1

经过调查后发现问题在于“没有对所有待签名参数按照字段名的 ASCII 码从小到大排序”导致。

解决方案

那么就需要对query参数进行自然排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function array_is_sorted($arr, $comparator){
$answer = true;
foreach ($arr as $key => $current) {
if(!isset($arr[$key + 1])) continue;
$next = $arr[$key + 1];
$answer = $answer && $comparator($current, $next);
}
return $answer;
}

function array_keys_is_sorted($arr) {
$keys = array_keys($arr);
return array_is_sorted($keys, function ($str1, $str2) {
return strnatcmp($str1, $str2) > 0 ? false : true;
});
}

需要以上两个函数,通过第二个函数可以判断数组的键名是否已经经过自然排序

在Laravel框架中使用如下(Middleware):

1
2
3
4
5
6
7
$query = $request->query();
// 若存在query并且query没有经过排序
if ($query && !array_keys_is_sorted($query)) {
ksort($query);// 进行排序
$url = $request->url().'?'.http_build_query($query);
return redirect($url);// 重定向到正确的URL
}

排序前:

1
http://example.com/page1?sharer_username=gh_f09a8z12&sharer_sharetime=1563663628&scene=0&clicktime=1563768946&from=timeline

排序后:

1
http://example.com/page1?clicktime=1563768946&from=timeline&scene=0&sharer_sharetime=1563663628&sharer_username=gh_f09a8z12

经测试, JSSDK现在可正常工作。