Laravel 接口签名
1.创建中间件VerifyApiSign
<?php
namespace App\Http\Middleware;
use Carbon\Carbon;
use Closure;
/**
* 接口签名
*
*/
class VerifyApiSign
{
// 忽略列表
protected $except = [
//
];
// 时间误差
protected $timeError = 5;
// 密钥
protected $secretKey = '';
// 签名字段
protected $signField = 'sign';
/* public function __construct()
{
$this->secretKey = config('auth.api_sign.secret_key', '');
}*/
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->inExceptArray($request) || ($this->allowTimestamp($request) && $this->signMatch($request))) {
return $next($request);
}
return response()->json([
'code' => '-1',
'msg' => '签名有误',
'data' => [],
]);
}
/**
* 判断当前请求是否在忽略列表中
*/
protected function inExceptArray($request)
{
foreach ($this->except as $except) {
if ($except !== '/') {
$except = trim($except, '/');
}
if ($request->fullUrlIs($except) || $request->is($except)) {
return true;
}
}
return false;
}
/**
* 判断用户请求是否在对应时间范围
*/
protected function allowTimestamp($request)
{
$queryTime = Carbon::createFromTimestamp($request->query('timestamp', 0));
$lfTime = Carbon::now()->subSeconds($this->timeError);
$rfTime = Carbon::now()->addSeconds($this->timeError);
if ($queryTime->between($lfTime, $rfTime, true)) {
return true;
}
return false;
}
/**
* 签名验证
*/
protected function signMatch($request)
{
$data = $request->query();
// 移除sign字段
if (isset($data['sign'])) {
unset($data['sign']);
}
ksort($data);
$sign = '';
foreach ($data as $k => $v) {
if ($this->signField !== $k) {
$sign .= $k . $v;
}
}
if (strtoupper(sha1(md5($sign . $this->secretKey))) === $request->query($this->signField, null)) {
return true;
}
return false;
}
}
2.打开App\Http\Kernel.php文件,添加我们之前创建的中间件
3.控制器模拟测试方法
public function test(){
//timestamp和sign为固定传入值,sign使用加密方法加密。
$time = time();
$array = [
'list' => 1,
'timestamp' => $time,
'sign' => ''
];
$sign = $this->arithmetic($array);
$array['sign'] = $sign;
/*$paramStr = '';
foreach ($array as $k => $v) {
$paramStr = $paramStr . $k . '=' . $v . '&';
}*/
$url_str = http_build_query($array);
$url = "http://test.com/api/test?".$url_str;
$result = $this -> httpGet($url);
print_r($result );exit;
}
/**
* 签名加密
*1. 对加密数组进行字典排序 防止因为参数顺序不一致而导致下面拼接加密不同
* 2. 将Key和Value拼接
* 3. 通过md5,sha1加密并转化为大写获得签名sign
* @param [type] $arr
* @return void
*/
private function arithmetic($arr){
ksort($arr);
$sign = '';
foreach ($arr as $k => $v) {
if ('sign' !== $k) {
$sign .= $k . $v;
}
}
$sign = md5($sign.$arr['sign']);
$sign = sha1($sign);
$sign = strtoupper($sign);
return $sign;
}
/**
* get请求
*
* @param [type] $url
* @return void
*/
private function httpGet($url){
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$url);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
$result = curl_exec($curl);
curl_close($curl);
return $result;
}