基于很多同學(xué)對(duì)接口簽名驗(yàn)證比較陌生,PhalApi提供了一個(gè)基本版的接口驗(yàn)證服務(wù)。主要是基于md5進(jìn)行的簽名生成,這個(gè)只能作為一般性的參考。大家可以在此基礎(chǔ)上進(jìn)行調(diào)整延伸。
默認(rèn)情況下,在./config/di.php
文件中去掉注釋便可開(kāi)啟此接口驗(yàn)證,即:
// 簽名驗(yàn)證服務(wù)
$di->filter = new \PhalApi\Filter\SimpleMD5Filter();
其驗(yàn)簽的算法如下(如注釋所示):
1、排除簽名參數(shù)(默認(rèn)是sign)
2、將剩下的全部參數(shù),按參數(shù)名字進(jìn)行字典排序
3、將排序好的參數(shù),全部用字符串拼接起來(lái)
4、進(jìn)行md5運(yùn)算
以下面的示例參數(shù)為例,即:
1、排除簽名參數(shù)(默認(rèn)是sign)
?service=Examples_CURD.Get&id=1
2、將剩下的全部參數(shù),按參數(shù)名字進(jìn)行字典排序
id=1
service=Examples_CURD.Get
3、將排序好的參數(shù),全部用字符串拼接起來(lái)
"1Examples_CURD.Get" = "1" + "Examples_CURD.Get"
4、進(jìn)行md5運(yùn)算
sign = 3ba5f5f03a90b2a648f5dd1df7387e26 = md5("1Examples_CURD.Get")
5、請(qǐng)求時(shí),加上簽名參數(shù)
?service=Examples_CURD.Get&id=1&sign=3ba5f5f03a90b2a648f5dd1df7387e26
下面是兩個(gè)調(diào)用示例,錯(cuò)誤請(qǐng)求下(即簽名失敗):
http://dev.phalapi.net/?service=Examples_CURD.Get&id=1&sign=xxx
返回:
{
"ret": 406,
"data": [],
"msg": "非法請(qǐng)求:簽名錯(cuò)誤"
}
溫馨提示:簽名錯(cuò)誤情況下,可以查看日記獲得正確的sign,如:
2017-07-22 12:02:18|DEBUG|Wrong Sign|{"needSign":"3ba5f5f03a90b2a648f5dd1df7387e26"}
正常請(qǐng)求下(帶sign簽名):
http://dev.phalapi.net/?service=Examples_CURD.Get&id=1&sign=3ba5f5f03a90b2a648f5dd1df7387e26
如果不想使用sign作為關(guān)鍵的簽名參數(shù),可以在注冊(cè)時(shí)指定,如使用縮寫s:
$di->filter = new \PhalApi\Filter\SimpleMD5Filter('s');
對(duì)于不需要進(jìn)行簽名驗(yàn)證的接口服務(wù),可以使用白名單配置,通過(guò)框架自身實(shí)現(xiàn)對(duì)指定配置的接口服務(wù)排除。即調(diào)用的接口服務(wù),如果配置了白名單,則不調(diào)用過(guò)濾器。
接口服務(wù)白名單配置是:app.service_whitelist
,即配置文件./config/app.php
里面的service_whitelist
配置,其默認(rèn)值是:
'service_whitelist' => array(
'Site.Index',
),
如源代碼里的注釋所示,配置的格式有以下四種。
類型 | 配置格式 | 匹配規(guī)則 | 示例及說(shuō)明 |
---|---|---|---|
全部 | *.* |
匹配全部接口服務(wù)(慎用?。?/td> | 如果配置了此規(guī)則,即全部的接口服務(wù)都不觸發(fā)過(guò)濾器。 |
方法通配 | Site.* |
匹配某個(gè)類的任何方法 | 即App\Api\Site接口類的全部方法 |
類通配 | *.Index |
匹配全部接口類的某個(gè)方法 | 即全部接口類的Index方法 |
具體匹配 | Site.Index |
匹配指定某個(gè)接口服務(wù) | 即App\Api\Site::Index() |
如果有多個(gè)生效的規(guī)則,按短路判斷原則,即有任何一個(gè)白名單規(guī)則匹配后就跳過(guò)驗(yàn)證,不觸發(fā)過(guò)濾器。
以下是更多的示例:
'service_whitelist' => array(
'*.Index', // 全部的Index方法
'Test.*', // Api_Test的全部方法
'User.GetBaseInfo', // Api_User::GetBaseInfo()方法
),
配置好上面的白名單后,以下這些接口服務(wù)全部不會(huì)觸發(fā)過(guò)濾器:
// 全部的Index方法
?service=Site.Index
?service=User.Index
// Api_Test的全部方法
?service=Test.DoSth
?service=Test.Hello
?service=Test.GOGOGO
// Api_User::GetBaseInfo()方法
?service=User.GetBaseInfo
通常關(guān)于接口簽名這塊,我們還需要:
/**
* 應(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),
),
如果我們需要實(shí)現(xiàn)簽名驗(yàn)證,只需要簡(jiǎn)單的兩步即可:
2、注冊(cè)過(guò)濾器服務(wù) PhalApi\DI()->filter;
下面以大家熟悉的 微信驗(yàn)簽 為例,進(jìn)行示例說(shuō)明。
通常我們約定返回ret = 402表示驗(yàn)證失敗,所以當(dāng)簽名失敗時(shí),我們可以返回ret = 402以告知客戶端簽名不對(duì)。根據(jù)微信的檢驗(yàn)signature的PHP示例代碼,我們可以快速實(shí)現(xiàn)自定義簽名規(guī)則,如:
// 文件 ./src/app/Common/SignFilter.php
<?php
namespace App\Common;
use PhalApi\Filter;
use PhalApi\Exception\BadRequestException;
class SignFilter implements Filter
{
public function check()
{
$signature = \PhalApi\DI()->request->get('signature');
$timestamp = \PhalApi\DI()->request->get('timestamp');
$nonce = \PhalApi\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 BadRequestException('wrong sign', 1);
}
}
}
隨后,我們只需要再簡(jiǎn)單地注冊(cè)一下過(guò)濾器服務(wù)即可,在./config/di.php
文件最后追加:
// 簽名驗(yàn)證服務(wù)
$di->filter = new App\Common\SignFilter();
更多建議: