簽名驗(yàn)證:自定義簽名規(guī)則

2018-11-21 21:16 更新

1.22.1 過濾器服務(wù)

正如我們核心思想DI里面所說的,我們把后臺(tái)很多功能資源都稱為服務(wù),所以在PhalApi框架中我們已經(jīng)系統(tǒng)規(guī)定了DI()->filter為過濾器服務(wù),以實(shí)現(xiàn)接口請(qǐng)求時(shí)的一些攔截操作,一如現(xiàn)在要說明的簽名驗(yàn)證。

在接口進(jìn)行初始化時(shí),會(huì)自動(dòng)調(diào)用已注冊(cè)的過濾器服務(wù) DI()->filter ,關(guān)鍵的代碼如下:

//$vim ./PhalApi/PhalApi/Api.php
    public function init()
    {
        $this->createMemberValue();

        $this->filterCheck();

        $this->checkStatus();
    }

    protected function filterCheck()
    {
        $filter = DI()->filter;

        if (isset($filter)) {
            $filter->check();
        }
    }

默認(rèn)直接可用的接口驗(yàn)證

基于很多同學(xué)對(duì)接口簽名驗(yàn)證比較陌生,從框架推出簽名驗(yàn)證以來,很長(zhǎng)一段時(shí)間內(nèi),很多同學(xué)對(duì)于如何實(shí)現(xiàn)一個(gè)接口簽名依然不知如何下手。
為了給大家更好的便利性,我們提供了一個(gè)基本版的接口驗(yàn)證服務(wù)。

主要是基于md5進(jìn)行的簽名生成,這個(gè)只能作為一般性的參考。大家可以在此基礎(chǔ)上進(jìn)行調(diào)整延伸。

默認(rèn)情況下,可以去掉注釋開啟使用PhalApi_Filter_SimpleMD5進(jìn)行接口驗(yàn)證,即:

//簽名驗(yàn)證服務(wù)
DI()->filter = 'PhalApi_Filter_SimpleMD5';

其驗(yàn)簽的算法如下(如注釋所示):

1、排除簽名參數(shù)(默認(rèn)是sign)
2、將剩下的全部參數(shù),按參數(shù)名字進(jìn)行字典排序
3、將排序好的參數(shù),全部用字符串拼接起來
4、進(jìn)行md5運(yùn)算

下面是兩個(gè)調(diào)用示例,錯(cuò)誤請(qǐng)求下(即簽名失敗):

http://localhost/phalapi/public/demo/?service=Default.Index&username=dogstar

返回:
{
    "ret": 406,
    "data": [],
    "msg": "非法請(qǐng)求:簽名錯(cuò)誤"
}

溫馨提示:
簽名錯(cuò)誤情況下,可以查看日志獲得正確的sign,如:

2015-10-23 23:16:16|DEBUG|Wrong Sign|{"needSign":"35321cc43cfc1e4008bf6f1bf9b7e3b8"}

正常請(qǐng)求下(帶sign簽名):

http://localhost/phalapi/public/demo/?service=Default.Index&username=dogstar&sign=35321cc43cfc1e4008bf6f1bf9b7e3b8

如果不想使用sign作為關(guān)鍵的簽名參數(shù),可以在注冊(cè)時(shí)指定,如使用縮寫s:

DI()->filter = new PhalApi_Filter_SimpleMD5('s');

1.22.2 微信簽名示例

所以,如果我們需要實(shí)現(xiàn)簽名驗(yàn)證,只需要簡(jiǎn)單的兩步即可:

  • 1、實(shí)現(xiàn)過濾器接口 PhalApi_Filter::check();
  • 2、注冊(cè)過濾器服務(wù) DI()->filter;

下面以大家熟悉的 微信驗(yàn)簽 為例,進(jìn)行示例說明。

(1)實(shí)現(xiàn)過濾器接口 PhalApi_Filter::check()

通常我們約定返回ret = 402表示驗(yàn)證失敗,所以當(dāng)簽名失敗時(shí),我們可以返回ret = 402以告知客戶端簽名不對(duì)。根據(jù)微信的檢驗(yàn)signature的PHP示例代碼,我們可以快速實(shí)現(xiàn)自定義簽名規(guī)則,如:

//$ vim ./Demo/Common/SignFilter.php 
<?php

class Common_SignFilter implements PhalApi_Filter
{
    public function check()
    {
        $signature = DI()->request->get('signature');
        $timestamp = DI()->request->get('timestamp');
        $nonce = DI()->request->get('nonce');  

        $token = 'Your Token Here ...';
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode( $tmpArr );
        $tmpStr = sha1( $tmpStr );

        if ($tmpStr != $signature) {
            throw new PhalApi_Exception_BadRequest('wrong sign', 1);
        }
    }
}

(2)注冊(cè)過濾器服務(wù) DI()->filter

隨后,我們只需要再簡(jiǎn)單地注冊(cè)一下過濾器服務(wù)即可,在init.php初始化文件最后追加:

//$ vim ./Public/init.php 
//簽名驗(yàn)證服務(wù)
DI()->filter = 'Common_SignFilter';

(3)運(yùn)行效果

當(dāng)我們?cè)俅握?qǐng)求接口時(shí),如默認(rèn)的服務(wù):/demo/?service=Default.Index,即會(huì)出現(xiàn)以下的錯(cuò)誤:apic

即:

{
    "ret": 401,
    "data": [
    ],
    "msg": "非法請(qǐng)求:wrong sign"
}

如果符合接口簽名的驗(yàn)證,則會(huì)正常返回我們熟悉的內(nèi)容,如:

/demo/?service=Default.Index&signature=b75e0a1b574d4e111a1d6ed3c9cfbe2ccdc09404&timestamp=123&nonce=123

會(huì)返回:

{
    "ret": 200,
    "data": {
        "title": "Default Api",
        "content": "PHPer您好,歡迎使用PhalApi!",
        "version": "1.1.0",
        "time": 1423055188
    },
    "msg": ""
}

1.22.3 特殊的場(chǎng)景

(1)個(gè)別接口不需要驗(yàn)簽?

在注冊(cè)好統(tǒng)一的接口驗(yàn)簽的過濾器攔截服務(wù)后,是會(huì)存在這樣一種情況:即個(gè)別的接口不需要簽名。

而這種情況,我們也是有考慮到的。所以在提供了公共的功能的情況下,我們是可以快速靈活地進(jìn)行定制化和擴(kuò)展。

當(dāng)我們個(gè)別的接口不需要簽名驗(yàn)證時(shí),只需要簡(jiǎn)單地在接口子類里面重定義過濾器的檢測(cè)即可,如在我們熟悉的默認(rèn)服務(wù)器取消簽名驗(yàn)證:

//vim ./Demo/Api/Default.php 
class Api_Default extends PhalApi_Api
{
    //....

    protected function filterCheck()
    {
    }
}

1.22.4 更好地建議

通常關(guān)于接口簽名這塊,我們還需要:

  • 1、為不同的接入方定義不同的密鑰和私鑰;

  • 2、如果業(yè)務(wù)需要,為各個(gè)接口、各個(gè)接入方分配調(diào)用權(quán)限;

  • 3、統(tǒng)一簽名參數(shù)的規(guī)則,可以配置在./Config/app.php中的,如上面的簽名需要的參數(shù),我們可以追加統(tǒng)一的參數(shù)規(guī)則:
    /**
     * 應(yīng)用接口層的統(tǒng)一參數(shù)
     */
    'apiCommonRules' => array(
        'signature' => array('name' => 'signature', 'require' => true),
        'timestamp' => array('name' => 'timestamp', 'require' => true),
        'nonce' => array('name' => 'nonce', 'require' => true),
    ),

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)