后端
/**
* 验证后返回
* @param $request
* @param \Closure $next
* @return mixed|\think\response\Json
*/
public function handle($request, \Closure $next)
{
try {
# 验证token 、可以直接加在路由后面
# 验证时间戳
$this->checkTime();
# 验证签名
$this->checkSign();
return $next($request);
} catch (Exception $exception) {
return json($exception->getMessage());
}
}
/**
* 验证时间戳
* @throws Exception
*/
public function checkTime()
{
$client_time = request()->get('timestamp') ?: request()->post('timestamp');
if (!is_numeric($client_time)) {
throw new Exception('时间戳格式不正确');
}
if (time() - $client_time > 120) {
throw new Exception('请求超时');
}
}
/**
* 验证签名
* @throws Exception
*/
public function checkSign()
{
$client_sign = request()->get('sign') ?: request()->post('sign');
# 判断是否有签名
if (!$client_sign) {
throw new Exception('签名不正确');
}
# 判断签名是否正确
$server_sign = $this->getSign();
if ($client_sign != $server_sign) {
throw new Exception('签名不正确');
}
}
/**
* 生成签名
* @return string
*/
public function getSign()
{
# 获取所有请求的参数
$params = request()->all();
# 签名规则
# 第一步 参与签名的参数不包括签名本身、不包括token
unset($params['sign']);
unset($params['token']);
# 第二步 按照ASCII进行参数排序
ksort($params);
$wait_sign = '';
foreach ($params as $key => $value) {
$wait_sign .= $key . '=' . $value . '&';
}
# 去除多余的& 符号
$wait_sign = rtrim($wait_sign, '&');
return md5($wait_sign);
}
前端生成签名(md5()方法是引入的js文件中的方法)
/**
* 生成签名
* @param params
* @returns {string}
*/
function create_sign(params) {
let timestamp = Math.ceil((new Date()).getTime() / 1000);
params['timestamp'] = timestamp;
let wait_sign = sort_ascii(params)
params['sign'] = md5(wait_sign);
return params;
}
/**
* 按ascii码从小到大排序
* @param obj
* @returns {string}
*/
function sort_ascii(obj) {
let arr = new Array();
let num = 0;
for (let i in obj) {
arr[num] = i;
num++;
}
let sortArr = arr.sort();
let str = ''; //自定义排序字符串
for (let i in sortArr) {
str += sortArr[i] + '=' + obj[sortArr[i]] + '&';
}
//去除两侧字符串
let char = '&'
str = str.replace(new RegExp('^\\' + char + '+|\\' + char + '+$', 'g'), '');
return str;
}