ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
##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,即会出现以下的错误: ![apic](http://webtools.qiniudn.com/20150411005257_2bf7d70e9a3a82cae524c03e0fcc6662) 即: ```javascript { "ret": 401, "data": [ ], "msg": "非法请求:wrong sign" } ``` 如果符合接口签名的验证,则会正常返回我们熟悉的内容,如: ```javascript /demo/?service=Default.Index&signature=b75e0a1b574d4e111a1d6ed3c9cfbe2ccdc09404&timestamp=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), ), ```