Laravel 简单接口签名验证

在做接口开发的时候,有时候需要提高一些接口安全性方面的工作,比如给接口添加签名等等。本文主要是我自己以前用过的接口签名的方式,放出来让大家见笑见笑。

MD5版

为了实现简单的MD5签名验证,我主要分三步走。

1. 创建文件

打开命令行,运行命令创建中间件。

php artisan make:middleware VerifyApiSign

创建成功后,可以在App\Http\Middleware目录下找到它。

2. 撸代码

不会撸代码没关系,这里可以使用魔法:选中内容,然后Ctrl+C→打开VerifyApiSign.php文件→Ctrl+V。嗯,保存退出。

<?php

namespace App\Http\Middleware;

use Carbon\Carbon;
use Closure;

/**
 * 接口签名
 *
 * @author Wenhsing <wenhsing@qq.com>
 */
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);
        }
        throw new \Exception('Signature error');
    }

    /**
     * 判断当前请求是否在忽略列表中
     *
     * @author Wenhsing <wenhsing@qq.com>
     *
     * @param  \Illuminate\Http\Request  $request
     * @return bool
     */
    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;
    }

    /**
     * 判断用户请求是否在对应时间范围
     *
     * @author Wenhsing <wenhsing@qq.com>
     *
     * @param \Illuminate\Http\Request $request
     * @return boolean
     */
    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;
    }

    /**
     * 签名验证
     *
     * @author Wenhsing <wenhsing@qq.com>
     *
     * @param \Illuminate\Http\Request $request
     * @return void
     */
    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 (md5($sign . $this->secretKey) === $request->query($this->signField, null)) {
            return true;
        }
        return false;
    }
}

3. 修改配置文件

打开config/auth.php修改配置文件,在配置后面添加我们的接口签名验证相关参数

<?php

return [
    // 这里省略了一些代码

    /*
    |--------------------------------------------------------------------------
    | Api Signature configuration
    |--------------------------------------------------------------------------
    */
    'api_sign' => [
        // 你的密钥串
        'secret_key' => env('API_SIGN_SECRET_KEY', ''),
    ],
];

打开App\Http\Kernel.php文件,在路由中间件组中的api字段中添加我们之前创建的中间件

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    // 这里省略了其他代码
   
    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        // 这里省略了其他代码

        'api' => [
            'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            // 接口签名中间件
            \App\Http\Middleware\VerifyApiSign::class,
        ],
    ];

    // 这里省略了其他代码
}

好了,你的接口就可以进行简单的接口签名验证了。其他类型的验证,之后再说。。。

posted @ 2021-01-19 10:49  Wenhsing  阅读(1418)  评论(0编辑  收藏  举报