多系統對接-簽名校驗案例

ZsmHub發表於2020-11-13

config/Sign.php

<?php

// 第三方平臺呼叫『當前系統』介面的簽名金鑰
return [
    // 簽名生命週期設定,單位秒
    'sign_ttl' => env('SIGN_TTL', 600),

    // 簽名型別
    'sign_type_xxx' => 'xxx', //  xxx系統
    'sign_type_test' => 'test', //  test系統

    // 金鑰
    'sign_type_secret' => [
        'xxx' => env('SIGN_SECRET_XXX', 'test_123456'),
        'test' => env('SIGN_SECRET_TEST', 'test_123456'),
    ],
];

app/Services/AuthSign.php

<?php

namespace App\Services;

// 第三方平臺請求的簽名校驗
class AuthSign
{
    /**
     * 簽名校驗
     * @param string $signType 簽名型別,對接哪個第三方系統的標識
     * @param string $sign 簽名
     * @param int $requestTime 請求時間戳
     * @return array
     */
    public static function checkSign(string $signType, string $sign, int $requestTime): array
    {
        // 簽名型別:新增對外介面簽名型別時,需要去配置新的簽名型別和金鑰
        $signSecret = config('sign.sign_type_secret')[$signType] ?? '';

        if ($signSecret == '') {
            return ['result' => false, 'msg' => '該簽名型別還沒配置'];
        }

        if ($sign != md5("{$requestTime}-{$signType}-{$signSecret}")) {
            return ['result' => false, 'msg' => '簽名有誤'];
        }

        $currentTime = time();
        if ($currentTime < $requestTime || ($currentTime-$requestTime) > config('sign.sign_ttl')) {
            return ['result' => false, 'msg' => '簽名已過期'];
        }

        return ['result' => true, 'msg' => '簽名校驗成功'];
    }

    /**
     * 生成簽名
     * @param string $signType 簽名型別,對接哪個第三方系統的標識
     * @return array
     */
    public static function getSign(string $signType): array
    {
        $signSecret = config('sign.sign_type_secret')[$signType] ?? '';
        if ($signSecret == '') {
            return ['result' => false, 'msg' => '該簽名型別還沒配置'];
        }
        $requestTime = time();
        return ['result' => true, 'time' => $requestTime, 'sign' => md5("{$requestTime}-{$signType}-{$signSecret}")];
    }
}

app/Http/Middleware/AuthSignTest.php

<?php

namespace App\Http\Middleware;

use App\Facades\Response;
use Symfony\Component\HttpFoundation\Response as FoundationResponse;
use Closure;

// 『test系統』請求『當前系統』介面的簽名校驗
class AuthSignTest
{
    public function handle($request, Closure $next)
    {
        $sign = $request->header('sign') ?: '';
        $time = $request->header('time') ? : '';

        if (empty($sign) || empty($time)) {
            return Response::fail('傳參有誤', [], FoundationResponse::HTTP_UNAUTHORIZED);
        }

        $signData = \App\Services\AuthSign::checkSign(config('sign.sign_type_test'), $sign, (int)$time);
        if (!$signData['result']) {
            return Response::fail("sign校驗失敗:{$signData['msg']}", [], FoundationResponse::HTTP_UNAUTHORIZED);
        }

        return $next($request);
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結
程式設計就像呼吸,學會那天起一日不敢荒廢。

相關文章