自定义对外开放接口的加解密和签名、验签

背景

公司需要对外开放接口,因此需要进行签名和验签。所以,自定义了一个签名和验签规则。

具体实现
  • 1.定义抽象类
<?php


namespace AppLibrarySignature;


abstract class AbstractSecret
{
    /**
     * 对接ID
     * @var string
     */
    protected $appId = 'ty808732';

    /**
     * @var string
     */
    protected $key = '6c340d5113a7689168796dd65d2391d9cd26a4859051467c';

    /**
     * 接口名
     * @var string
     */
    protected $method = 'chip.api.goods.list';

    /**
     * 商户号
     * @var string
     */
    protected $partnerId = 'chip';

    /**
     * 渠道服务编码
     * @var int
     */
    protected $channelType = 5900;

    /**
     * 版本号
     * @var int
     */
    protected $version = 'V1';

    /**
     * 数据格式
     * @var int
     */
    protected $dateType = 'json';

    /**
     * 字符
     * @var string
     */
    protected $charset = 'utf-8';


    /**
     * 对接密钥
     * @var string
     */
    //protected static $secretKey = 'zYYB0E8YdyNwuveyJUDGWr';//测试
    protected $secretKey = 'I1pFucrCa78EO9BrNocNuS';//生产


    /**
     * 请求参数
     * @var array
     */
    protected $item;

}
  • 2.封装签名规则
<?php


namespace AppLibrarySignature;

/**
 * 加解密demo
 * Class Secret
 * @package AppLibrarySignature
 */
class Secret extends AbstractSecret
{
    /**
     * 加密类
     * @var object
     */
    private $encrypt;

    /**
     * 解密类
     * @var object
     */
    private $decrypt;


    public function __construct($item,$key='')
    {
        $this->item = $item;
        if($key) $this->key = $key;
        $this->encrypt = new Encrypt();
        $this->decrypt = new Decrypt();
    }

    /**
     * @return array
     * @throws Exception
     */
    public function encrypt()
    {
        if(!$this->item){
            throw new Exception('业务参数不能为空');
        }
        $bizContent = $this->item;
        if(is_array($bizContent)){
            $bizContent = json_encode($bizContent,1);
        }
        $request = $this->baseRequest($bizContent);
        ksort($request);
        $secret = urldecode(http_build_query($request));
        $sign   = md5(sha1($secret));
        $sign   = base64_encode(strtoupper($sign));
        $request['sign'] = $sign;
        $request['sign_type'] = 'MD5';
        unset($request['key']);

        return $request;

    }

    /**
     * @param string $biz_content
     * @param null $datetime
     * @return array
     */
    private function baseRequest(string $biz_content, $datetime = null)
    {
        $request = [
            'partner_id' => $this->partnerId,
            'method' => $this->method,
            'format' => 'JSON',
            'charset' => 'utf-8',
            'time_stamp' => $datetime ?: date('Y-m-d H:i:s'),
            'version' => '2.0',
            'app_id' => $this->appId,
            'channel_type' => $this->channelType,
            'biz_content' => $this->encrypt->encrypt3DES($biz_content),
            'key' => $this->secretKey,
        ];
        unset($this->encrypt);
        return $request;
    }
}
  • 3.对数据进行验签
<?php

namespace AppLibrarySignature;


use AppModelChipmallApiModel;

/**
 * 签名
 * Class Signature
 * @package AppLibrarySignature
 */
class Signature extends AbstractSecret
{

    /**
     * @return array
     */
    private function baseRequest()
    {
        $timestamp = empty($this->item['time_stamp'])
            ? date('Y-m-d H:i:s')
            : $this->item['time_stamp'];

        $request = [
            'partner_id'    => $this->partnerId,
            'method'        => $this->method,
            'format'        => $this->dateType,
            'charset'       => $this->charset,
            'time_stamp'    => $timestamp,
            'version'       => $this->version,
            'app_id'        => $this->appId,
            'channel_type'  => $this->channelType,
            'biz_content'   => $this->item['biz_content'],
            'key'           => $this->secretKey,
        ];

        return $request;
    }

    private function getAppInfo($appId)
    {
        if(!isset($appId) || empty($appId)){
            throw new Exception('App ID not allow empty');
        }
        $appInfo = ChipmallApiModel::where('app_id',$appId)->first();
        if(!$appInfo){
            throw new Exception('App Info is null');
        }

        $this->appId        = $appInfo->app_id;
        $this->key          = $appInfo->app_sign;
        $this->method       = $appInfo->type;
        $this->channelType  = $appInfo->channel ?: 5900;
        $this->partnerId    = $appInfo->partner_id;
        $this->version      = $appInfo->version;
        $this->dateType     = $appInfo->data_type;

        unset($appInfo);

        return $this;
    }


    /**
     * @return array
     * @throws Exception
     */
    public function sign()
    {
        if(!$this->item){
            throw new Exception('Business parameters cannot be empty');
        }
        if (!isset($this->item['time_stamp']) || empty($this->item['time_stamp'])) {
            throw new Exception('timestamp is empty');
        }
        if (!isset($this->item['biz_content']) || empty($this->item['biz_content'])) {
            throw new Exception('Biz content is empty');
        }

        $request = $this->baseRequest();
        ksort($request);
        $secret = urldecode(http_build_query($request));
        $sign   = md5(sha1($secret));
        $sign   = base64_encode(strtoupper($sign));
        $request['sign'] = $sign;
        $request['sign_type'] = 'sha1';
        unset($request['key']);

        return $request;

    }


    /**
     * 验签
     * @param string $sign
     * @return $this
     * @throws Exception
     */
    public function verifySign(string $sign)
    {

        if(!$this->item){
            throw new Exception('Business parameters cannot be empty');
        }

        if(!isset($this->item['app_id']) || empty($this->item['app_id'])){
            throw new Exception('App ID is empty');
        }

        if(!isset($this->item['time_stamp']) || empty($this->item['time_stamp'])){
            throw new Exception('timestamp is empty');
        }

        $appId = $this->item['app_id'];

        $this->getAppInfo($appId);

        $encrypt = $this->sign();
        $appSign = $encrypt['sign'];

        if (!isset($sign) || empty($sign)) {
            throw new Exception('Signature is empty');
        }

        if ($appSign != $sign) {
            throw new Exception('Signature verification failed');
        }

        return $this;
    }


}
  • 4.数据进行加密
<?php

namespace AppLibrarySignature;

/**
 * 加密
 * Class Encrypt
 * @package AppLibrarySignature
 */
class Encrypt  extends AbstractSecret
{
    /**
     * 加密3DES
     * @param string $encrypt 需要加密的数据
     * @return string
     */
    public function encrypt3DES($encrypt)
    {
        $out = openssl_encrypt($encrypt, 'DES-EDE3', $this->key, OPENSSL_RAW_DATA);
        $encrypt = base64_encode($out);

        return $encrypt;
    }

    /**
     * 加密AES-128-ECB
     * @param string $encrypt 需要加密的数据
     * @return string
     */
    public function encrypt($encrypt) {
        $encrypted = openssl_encrypt($encrypt, 'AES-128-ECB', $this->key, OPENSSL_RAW_DATA);
        return base64_encode($encrypted);
    }
}
  • 5.数据进行解密
<?php

namespace AppLibrarySignature;

/**
 * 解密
 * Class Decrypt
 * @package AppLibrarySignature
 */
class Decrypt extends AbstractSecret
{


    /**
     * 解密AES-128-ECB
     * @param string $data 需要解密的数据
     * @return string
     */
    public function decrypt($data) {
        $decrypted = base64_decode($data);
        return openssl_decrypt($decrypted, 'AES-128-ECB', $this->key, OPENSSL_RAW_DATA);
    }

    /**
     * 解密3DES
     * @param string $data 需要解密的数据
     * @return false|string
     */
    public function decrypt3DES($data)
    {
        $key = base64_decode($this->key);
        $decrypted = openssl_decrypt($data,'DES-EDE3',$key,OPENSSL_RAW_DATA);

        return $decrypted;
    }

}

以上是我根据自己项目需要封装的加解密和验签。你可以根据你的项目实际需要进行封装。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>