##1.22.1 過濾器服務
正如我們核心思想DI里面所說的,我們把后臺很多功能資源都稱為服務,所以在PhalApi框架中我們已經系統規定了**DI()->filter**為過濾器服務,以實現接口請求時的一些攔截操作,一如現在要說明的簽名驗證。
在接口進行初始化時,會自動調用已注冊的過濾器服務 **DI()->filter** ,關鍵的代碼如下:
```javascript
//$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();
}
}
```
###默認直接可用的接口驗證
基于很多同學對接口簽名驗證比較陌生,從框架推出簽名驗證以來,很長一段時間內,很多同學對于如何實現一個接口簽名依然不知如何下手。
為了給大家更好的便利性,我們提供了一個基本版的接口驗證服務。
主要是基于md5進行的簽名生成,這個只能作為一般性的參考。大家可以在此基礎上進行調整延伸。
默認情況下,可以去掉注釋開啟使用PhalApi_Filter_SimpleMD5進行接口驗證,即:
```javascript
//簽名驗證服務
DI()->filter = 'PhalApi_Filter_SimpleMD5';
```
其驗簽的算法如下(如注釋所示):
```javascript
1、排除簽名參數(默認是sign)
2、將剩下的全部參數,按參數名字進行字典排序
3、將排序好的參數,全部用字符串拼接起來
4、進行md5運算
```
下面是兩個調用示例,錯誤請求下(即簽名失敗):
```
http://localhost/phalapi/public/demo/?service=Default.Index&username=dogstar
返回:
{
"ret": 406,
"data": [],
"msg": "非法請求:簽名錯誤"
}
```
> 溫馨提示:
> 簽名錯誤情況下,可以查看日志獲得正確的sign,如:
```
2015-10-23 23:16:16|DEBUG|Wrong Sign|{"needSign":"35321cc43cfc1e4008bf6f1bf9b7e3b8"}
```
正常請求下(帶sign簽名):
```
http://localhost/phalapi/public/demo/?service=Default.Index&username=dogstar&sign=35321cc43cfc1e4008bf6f1bf9b7e3b8
```
如果不想使用sign作為關鍵的簽名參數,可以在注冊時指定,如使用縮寫s:
```
DI()->filter = new PhalApi_Filter_SimpleMD5('s');
```
##1.22.2 微信簽名示例
所以,如果我們需要實現簽名驗證,只需要簡單的兩步即可:
+ 1、實現過濾器接口 **PhalApi_Filter::check()**;
+ 2、注冊過濾器服務 **DI()->filter**;
下面以大家熟悉的 [微信驗簽](http://mp.weixin.qq.com/wiki/17/2d4265491f12608cd170a95559800f2d.html) 為例,進行示例說明。
###(1)實現過濾器接口 PhalApi_Filter::check()
通常我們約定返回ret = 402表示驗證失敗,所以當簽名失敗時,我們可以返回ret = 402以告知客戶端簽名不對。根據微信的檢驗signature的PHP示例代碼,我們可以快速實現自定義簽名規則,如:
```javascript
//$ 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)注冊過濾器服務 DI()->filter
隨后,我們只需要再簡單地注冊一下過濾器服務即可,在init.php初始化文件最后追加:
```javascript
//$ vim ./Public/init.php
//簽名驗證服務
DI()->filter = 'Common_SignFilter';
```
###(3)運行效果
當我們再次請求接口時,如默認的服務:/demo/?service=Default.Index,即會出現以下的錯誤:

即:
```javascript
{
"ret": 401,
"data": [
],
"msg": "非法請求:wrong sign"
}
```
如果符合接口簽名的驗證,則會正常返回我們熟悉的內容,如:
```javascript
/demo/?service=Default.Index&signature=b75e0a1b574d4e111a1d6ed3c9cfbe2ccdc09404×tamp=123&nonce=123
```
會返回:
```javascript
{
"ret": 200,
"data": {
"title": "Default Api",
"content": "PHPer您好,歡迎使用PhalApi!",
"version": "1.1.0",
"time": 1423055188
},
"msg": ""
}
```
##1.22.3 特殊的場景
###(1)個別接口不需要驗簽?
在注冊好統一的接口驗簽的過濾器攔截服務后,是會存在這樣一種情況:即個別的接口不需要簽名。
而這種情況,我們也是有考慮到的。所以在提供了公共的功能的情況下,我們是可以快速靈活地進行定制化和擴展。
當我們個別的接口不需要簽名驗證時,只需要簡單地在接口子類里面重定義過濾器的檢測即可,如在我們熟悉的默認服務器取消簽名驗證:
```javascript
//vim ./Demo/Api/Default.php
class Api_Default extends PhalApi_Api
{
//....
protected function filterCheck()
{
}
}
```
##1.22.4 更好地建議
通常關于接口簽名這塊,我們還需要:
+ 1、為不同的接入方定義不同的密鑰和私鑰;
+ 2、如果業務需要,為各個接口、各個接入方分配調用權限;
+ 3、統一簽名參數的規則,可以配置在./Config/app.php中的,如上面的簽名需要的參數,我們可以追加統一的參數規則:
```javascript
/**
* 應用接口層的統一參數
*/
'apiCommonRules' => array(
'signature' => array('name' => 'signature', 'require' => true),
'timestamp' => array('name' => 'timestamp', 'require' => true),
'nonce' => array('name' => 'nonce', 'require' => true),
),
```
- 歡迎使用PhalApi!
- 接口,從簡單開始!
- [1.1]-下載與安裝
- [1.2]-創建一個自己的項目
- [1.3]-在線體驗
- [1.4]-文檔、幫助和官網
- [1.10]-對PhalApi框架的抉擇
- [1.11]-快速入門(backup)
- [1.12]-參數規則:接口參數規則配置
- [1.13]-統一的接口請求方式:_sevice=XXX.XXX
- [1.14]-統一的返回格式和結構:ret-data-msg
- [1.15]-數據庫操作:基于NotORM的使用及優化
- [1.16]-配置讀取:內外網環境配置的完美切換
- [1.17]-日記紀錄:簡化版的日記接口
- [1.18]-快速函數:人性化的關懷
- [1.19]-DI服務速查:各資源服務一覽表
- [1.20]-DB操作:數據庫基本操作速查
- [1.21]-類的自動加載:遵循PEAR包的命名規范
- [1.22]-簽名驗證:自定義簽名規則
- [1.23]-請求和響應:GET和POST兩者皆可得及超越JSON格式返回
- [1.24]-緩存策略:更靈活地可配置化的多級緩存
- [1.25]-國際化翻譯:為走向國際化提前做好翻譯準備
- [1.26]-數據安全:數據對稱加密方案
- [1.27]-精益開發:更富表現力的Model層和重量級數據獲取的應對方案
- [1.28]-COOKIE:對COOKIE原生態的支持及記憶加密升級版
- [1.29]-開放與封閉:多入口和統一初始化
- [1.30]-保持的力量:接口開發最佳實踐
- [1.31]-新型計劃任務:以接口形式實現的計劃任務
- [2.11]-核心思想:DI依賴注入-讓資源更可控
- [2.12]-海量數據:可配置的分庫分表
- [2.13]-接口調試:在線SQL語句查看與性能優化
- [2.14]-測試驅動開發:意圖導向編程下的接口開發
- [2.15]-演進:新型計劃任務續篇
- [2.16]-領域驅動設計:應對復雜領域業務的Domain層
- [2.17]-微服務:Api接口服務層
- [2.18]-定制化:資源服務的再實現
- [2.19]-擴展庫:可重用的擴展類庫
- [2.20]-約定編程:架構明顯的編程風格
- [2.21]-服務器統一部署方案簡明版:CentOs---Nginx---php-fpm---MySql-[--Memcached]
- [2.22]-更多工具:精益項目和團隊建設
- [3.1]-擴展類庫:微信開發
- [3.2]-擴展類庫:代理模式下phprpc協議的輕松支持
- [3.3]-擴展類庫:基于PHPMailer的郵件發送
- [3.4]-擴展類庫:優酷開放平臺接口調用
- [3.5]-擴展類庫:七牛云存儲接口調用
- [3.6]-擴展類庫:新型計劃任務
- [3.8]-擴展類庫:用戶、會話和第三方登錄集成
- [3.9]-擴展類庫:swoole支持下的長鏈接和異步任務實現
- [3.11]-擴展類庫:基于FastRoute的快速路由
- [4.2]-開發實戰2:模擬優酷開放平臺接口項目開發
- [4.3]-開發實戰3:一個簡單的小型項目開發(奔跑吧兄弟投票活動)
- [5.1]-架構與思想:PhalApi核心設計和思想解讀
- [5.2]-雜談:扯一些PhalApi的前世和今生
- [5.3]-框架總結:術語表和PHP開發建議
- [5.4]-許可
- [5.5]-聯系和加入我們
- [5.6]-更新日記
- [5.8]-致框架貢獻者:加入PhalApi開源指南
- [6.1]-基于接口查詢語言的SDK包
- [6.2]-SDK包(JAVA版)
- [6.3]-SDK包(PHP版)
- [6.4]-SDK包(Objective-C版)
- [6.5]-SDK包(javascript版)
- [6.6]-SDK包(Ruby版)
- [8.1]-PhalApi視頻教程
- 附錄1:接口文檔參考模板