实现接口权限验证
开发用户接口实例之前,还需要设计一套严格的接口验证方法,保证 API 接口的安全
性。常见的接口验证一般包含以下几种
- 请求时间:接口时效性验证。为了防止大 的重复请求, 可以设置每次请求的时效 小到以秒为单位, 大到可以是半个 小时
- 验签:参数完整性验证。一般接口攻击, 都会截获请求,附带额外参数进行攻击,需要进行过滤验证。此时就需要客户端把所有的请求参 数根据一个特定的算法,生成一个签名字符串,并在请求时一并发送。服务器接收到这个 签名字符串后进行验证。
- token:用户唯一Token 。用户每次登录都会生成唯 Token 信息,注销或者超时会话时 Token 会被注销,防止被非法获取
根据以上设计思路,本实例设计基于时效和参数 效验的权限验证方法。接口验证流程如图所示 下面以 ThinkP 框架为例,查看实现接口验 证父类的步骤与方法。
下面以 ThinkP 框架为例,查看实现接口验
证父类的步骤与方法。
实现权限验证基类
在application 目录下创建名为 api 应用模块 随后新建控制器 Api lp 作步骤如下。
(1 )定义返回值方法
api.php 控制器文件中 新增以下方法
/*
* 数据返回
* @param string $code HTTP CODE
* @param string message 提示信息
* @param array $data 返回数据
*/
public function return_msg($code="200", $message="成功", $data= [)){
header('Content-Type:application/json');//设置返回类型
http_response_code($code);//设置返回头部
$return['code'] = $code ;
$return['message'] =$message ;
if(!empty($data)){
$return['data '] =$data;
}
exit(json_encode($return, JSON_UNESCAPED_UNICODE));
}
此方法用来定义返回信息操作,其中定义了 HTTP Header 类型和编码,代码如下:
header(‘Content-Type:application/json’);//设置返回类型
http_response_code($code);//设置返回头部
把传入的参数组装为数组,返回 JSON 格式数据,代码如下
$return['code'] = $code ;
$return['message'] =$message ;
if(!empty($data)){
$return['data '] =$data;
}
exit(json_encode($return, JSON_UNESCAPED_UNICODE));
(2 )定义接口时效性验证方法
定义接口 验证方法,代码如下:
/**
*检测接口 是否超时
* @pa ram $arr
*/
public function check_time($arr) {
//设置返回类型
//设置返回头部
if(!isset($arr["time"])|| intval($arr["time"])<=1){
$this_return_msg(400, '时间戳错误 !');
}
if(time()- intval($arr["time"]) >$this->timeout_second){
$this_return_msg(400, ' 请求超时!');
}
该方法中进行了两部分验证 时间参数(time )是否非空验证和是否超时验证。如果
任意一项无法匹配,方法都会返回错误信息。其 $this- timeout_second 属性,定义了接
口时效是多少秒,在类中定义为属性,代码如下 :
//默认接口的有效期为 60
protected $timeout_second = 60 ;
(3 )定义生成接口签名方法
为了防止请求中带有其他恶意的参数 需要根据原始数据,定义签名生成方法,代
如下:
/**
*构建请求签名
* @param pa ram
* @return string
*/
public function buildSign($param){
unset($param["sign"]);//sign 字段不需要加入签名算法
unset($param["time "]);//time 字段不需要加入签名算法
ksort($param);//键值对的 key 按照升序排序
$str=implode("",$param);//请求参数值拼接成字符串
$sign =md5(md5($str).$this->sign_key);//执行加密
return $sign ;
}
buildSign()方法中,生成签名的算法主要有以下3步
- 对请求参数 数组进行排序 使用 PHP 中的
ksort()
方法进行排序。 - 把排序结果转换为字符串。
- 使用
md5()
方法和默认签名的 Key 进行签名生成的运算。
其中 $this- sign_key 属性值在类中定义 代码如下。 签名 Key 可以是动态的,只要能和客户端在生成签名时保持一致即可。
//执行 key
private $sign_key = 'ThinkPHPS ';
(4)定义签名验证方法
该方法把请求接口的参数值,先进行排序和字符串转换,然后再进行生成签名处理。
返回值中所带的签名,如果和验证参数值生成的签名值保持 ,则通过验证,反之则
示错误信息。该方法定义如下
/**
*验证请求签名是否正确
*@param $param
*/
public function check_sign($param ){
if(!issert($param["sign"])||!$param["sign"]){
$this_return_msg(400, ' 签名不能为空!');
}
if( $param["sign"]!== $this->buildSign($param)){
$this_return_msg(400, '签名错误!');
}
}
(5)在初始化方法中调用验证
验证方法定义完成后 需要在控制器的初始化方法中调用,代码定义如下:
//初始化方法
public function _initialize(){
parent::_initialize();
//获取请求对象
$this->request= Request::instance();
//是否开启 API 权限验证(方便测试)
if(confid("api_auth")){
//验证时间戳是否超时
$this->check_time($this->request->only(["time"]));
//验证签名是否正确
$this->check_sign($this->request->param());
}
}
需要注意的是,初始化方法中不仅获取了请求对象
$this->request= Request::instance();
还使用了系统配置,来定义是否开启验证(方便开发者模式)
if(confid("api_auth"))
application api config.php
文件中,定义如下
<?php
II API 块设计
return [
//应用命名空间
'api_auth' => true
]
访问地址 若效果如图,则说明 API 接口的全局验证成功
奇奇怪怪的只是又增加了呢
为了快速生成控制器类 在命令行下切换到应用根目 录下,执行 以下命令:
php think make:controller api/User
系统会自动生成 User 资源控制器类,并创建对应资源操作的几个方法。为了在URL 中可以访问资源,则需要定义资源路由规则。在 application 目录下的 route,php 文件
中,追加以下内容:
Route::resource('users','api/User');
按资源路由的注册方法,定义 个名为 users 的路由, 其实内部会自动注册 个路由
规则,详细对应关系如表
请求表示 | 请求类型 | 路由规则 | 对应操作方法 | 描述 |
---|---|---|---|---|
index | GET | users | index | 显示用户列表 |
create | GET | users/create | create | 新增用户页面 |
save | POST | users | save | 保存用户信息 |
read | GET | users/:id | read | 查看用户信息 |
edit | GET | users/:id/edit | edit | 编辑用户页面 |
update | PUT | users/:id | update | 更新用户信息 |
delete | DELETE | users/:id | delete | 删除用户 |
转载:https://blog.csdn.net/wangzhae/article/details/115019627