##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×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:接口文档参考模板