Yii2框架RESTful API 格式化响应,授权认证和速率限制三部分详解


Posted in PHP onNovember 10, 2016

之前写过一篇Yii2框架制作RESTful风格的API快速入门教程,今天接着来探究一下Yii2 RESTful的格式化响应,授权认证和速率限制三个部分

一、目录结构

先列出需要改动的文件。目录如下:

web
├─ common
│ └─ models 
│ └ User.php
└─ frontend
├─ config
│ └ main.php
└─ controllers
└ BookController.php

二、格式化响应

Yii2 RESTful支持JSON和XML格式,如果想指定返回数据的格式,需要配置yii\filters\ContentNegotiator::formats属性。例如,要返回JSON格式,修改frontend/controllers/BookController.php,加入红色标记代码:

namespace frontend\controllers;
use yii\rest\ActiveController;
use yii\web\Response;
class BookController extends ActiveController
{
public $modelClass = 'frontend\models\Book';
public function behaviors() {
$behaviors = parent::behaviors();
$behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
return $behaviors;
}
}

返回XML格式:FORMAT_XML。formats属性的keys支持MIME类型,而values必须在yii\web\Response::formatters中支持被响应格式名称。

三、授权认证

RESTful APIs通常是无状态的,因此每个请求应附带某种授权凭证,即每个请求都发送一个access token来认证用户。

1.配置user应用组件(不是必要的,但是推荐配置):

设置yii\web\User::enableSession属性为false(因为RESTful APIs为无状态的,当yii\web\User::enableSession为false,请求中的用户认证状态就不能通过session来保持)

设置yii\web\User::loginUrl属性为null(显示一个HTTP 403 错误而不是跳转到登录界面)

具体方法,修改frontend/config/main.php,加入红色标记代码:

'components' => [
...
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
'enableSession' => false,
'loginUrl' => null,
],
...
]

2.在控制器类中配置authenticator行为来指定使用哪种认证方式,修改frontend/controllers/BookController.php,加入红色标记代码:

namespace frontend\controllers;
use yii\rest\ActiveController;
use yii\web\Response;
use yii\filters\auth\CompositeAuth;
use yii\filters\auth\QueryParamAuth;
class BookController extends ActiveController
{
public $modelClass = 'frontend\models\Book';
public function behaviors() {
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => CompositeAuth::className(),
'authMethods' => [
/*下面是三种验证access_token方式*/
//1.HTTP 基本认证: access token 当作用户名发送,应用在access token可安全存在API使用端的场景,例如,API使用端是运行在一台服务器上的程序。
//HttpBasicAuth::className(),
//2.OAuth 2: 使用者从认证服务器上获取基于OAuth2协议的access token,然后通过 HTTP Bearer Tokens 发送到API 服务器。
//HttpBearerAuth::className(),
//3.请求参数: access token 当作API URL请求参数发送,这种方式应主要用于JSONP请求,因为它不能使用HTTP头来发送access token
//http://localhost/user/index/index?access-token=123
QueryParamAuth::className(),
],
];
$behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
return $behaviors;
}
}

3.创建一张user表

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
`password_hash` varchar(100) NOT NULL DEFAULT '' COMMENT '密码',
`password_reset_token` varchar(50) NOT NULL DEFAULT '' COMMENT '密码token',
`email` varchar(20) NOT NULL DEFAULT '' COMMENT '邮箱',
`auth_key` varchar(50) NOT NULL DEFAULT '',
`status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '状态',
`created_at` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`updated_at` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
`access_token` varchar(50) NOT NULL DEFAULT '' COMMENT 'restful请求token',
`allowance` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'restful剩余的允许的请求数',
`allowance_updated_at` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'restful请求的UNIX时间戳数',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `access_token` (`access_token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'admin', '$2y$13$1KWwchqGvxDeORDt5pRW.OJarf06PjNYxe2vEGVs7e5amD3wnEX.i', '', '', 'z3sM2KZvXdk6mNXXrz25D3JoZlGXoJMC', '10', '1478686493', '1478686493', '123', '4', '1478686493');

在common/models/User.php类中实现 yii\web\IdentityInterface::findIdentityByAccessToken()方法。修改common/models/User.php,加入红色标记代码::

public static function findIdentityByAccessToken($token, $type = null)
{
//findIdentityByAccessToken()方法的实现是系统定义的
//例如,一个简单的场景,当每个用户只有一个access token, 可存储access token 到user表的access_token列中, 方法可在User类中简单实现,如下所示:
return static::findOne(['access_token' => $token]);
//throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
}

四、速率限制

为防止滥用,可以增加速率限制。例如,限制每个用户的API的使用是在60秒内最多10次的API调用,如果一个用户同一个时间段内太多的请求被接收,将返回响应状态代码 429 (这意味着过多的请求)。

1.Yii会自动使用yii\filters\RateLimiter为yii\rest\Controller配置一个行为过滤器来执行速率限制检查。如果速度超出限制,该速率限制器将抛出一个yii\web\TooManyRequestsHttpException。

修改frontend/controllers/BookController.php,加入红色标记代码:

namespace frontend\controllers;
use yii\rest\ActiveController;
use yii\web\Response;
use yii\filters\auth\CompositeAuth;
use yii\filters\auth\QueryParamAuth;
use yii\filters\RateLimiter;
class BookController extends ActiveController
{
public $modelClass = 'frontend\models\Book';
public function behaviors() {
$behaviors = parent::behaviors();
$behaviors['rateLimiter'] = [
'class' => RateLimiter::className(),
'enableRateLimitHeaders' => true,
];
$behaviors['authenticator'] = [
'class' => CompositeAuth::className(),
'authMethods' => [
/*下面是三种验证access_token方式*/
//1.HTTP 基本认证: access token 当作用户名发送,应用在access token可安全存在API使用端的场景,例如,API使用端是运行在一台服务器上的程序。
//HttpBasicAuth::className(),
//2.OAuth 2: 使用者从认证服务器上获取基于OAuth2协议的access token,然后通过 HTTP Bearer Tokens 发送到API 服务器。
//HttpBearerAuth::className(),
//3.请求参数: access token 当作API URL请求参数发送,这种方式应主要用于JSONP请求,因为它不能使用HTTP头来发送access token
//http://localhost/user/index/index?access-token=123
QueryParamAuth::className(),
],
];
$behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
return $behaviors;
}
}

2.在user表中使用两列来记录容差和时间戳信息。为了提高性能,可以考虑使用缓存或NoSQL存储这些信息。

修改common/models/User.php,加入红色标记代码:

namespace common\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
use yii\filters\RateLimitInterface;
class User extends ActiveRecord implements IdentityInterface, RateLimitInterface
{
....
// 返回在单位时间内允许的请求的最大数目,例如,[10, 60] 表示在60秒内最多请求10次。
public function getRateLimit($request, $action)
{
return [5, 10];
}
// 返回剩余的允许的请求数。
public function loadAllowance($request, $action)
{
return [$this->allowance, $this->allowance_updated_at];
}
// 保存请求时的UNIX时间戳。
public function saveAllowance($request, $action, $allowance, $timestamp)
{
$this->allowance = $allowance;
$this->allowance_updated_at = $timestamp;
$this->save();
}
....
public static function findIdentityByAccessToken($token, $type = null)
{
//throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
//findIdentityByAccessToken()方法的实现是系统定义的
//例如,一个简单的场景,当每个用户只有一个access token, 可存储access token 到user表的access_token列中, 方法可在User类中简单实现,如下所示:
return static::findOne(['access_token' => $token]);
}
....
}

以上所述是小编给大家介绍的Yii2框架RESTful API 格式化响应,授权认证和速率限制三部分详解 ,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

PHP 相关文章推荐
php扩展ZF――Validate扩展
Jan 10 PHP
谈PHP生成静态页面分析 模板+缓存+写文件
Aug 17 PHP
PHP MemCached 高级缓存应用代码
Aug 05 PHP
上传文件先创建目录 再上传到目录里面去
Dec 29 PHP
有关于PHP中常见数据类型的汇总分享
Jan 06 PHP
使用PHP备份MYSQL数据的多种方法
Jan 15 PHP
PHP经典面试题之设计模式(经常遇到)
Oct 15 PHP
php ajax实现文件上传进度条
Mar 29 PHP
php数组分页实现方法
Apr 30 PHP
Thinkphp框架开发移动端接口(2)
Aug 18 PHP
php中简单的对称加密算法实现
Jan 05 PHP
PHPTree――php快速生成无限级分类
Mar 30 PHP
PHP基于反射机制实现插件的可插拔设计详解
Nov 10 #PHP
PHP yii实现model添加默认值的方法(两种方法)
Nov 10 #PHP
PHP实现的曲线统计图表示例
Nov 10 #PHP
PHP  Yii清理缓存的实现方法
Nov 10 #PHP
PHP模拟http请求的方法详解
Nov 09 #PHP
Linux平台PHP5.4设置FPM线程数量的方法
Nov 09 #PHP
浅析php-fpm静态和动态执行方式的比较
Nov 09 #PHP
You might like
PHP调用三种数据库的方法(3)
2006/10/09 PHP
用PHP为SHOPEX增加日志功能代码
2010/07/02 PHP
ThinkPHP 防止表单重复提交的方法
2011/08/08 PHP
thinkphp实现图片上传功能分享
2014/03/04 PHP
在Laravel中使用GuzzleHttp调用第三方服务的API接口代码
2019/10/15 PHP
javascript写的日历类(基于pj)
2010/12/28 Javascript
Javascript中的window.event.keyCode使用介绍
2011/04/26 Javascript
浅析JavaScript中两种类型的全局对象/函数
2013/12/05 Javascript
Vue.js报错Failed to resolve filter问题的解决方法
2016/05/25 Javascript
完美的js div拖拽实例代码
2016/09/24 Javascript
基于Vuejs框架实现翻页组件
2020/06/29 Javascript
详解JS: reduce方法实现 webpack多文件入口
2017/02/14 Javascript
vue.js 添加 fastclick的支持方法
2018/08/28 Javascript
ES6中Promise的使用方法实例总结
2020/02/18 Javascript
[49:40]2018DOTA2亚洲邀请赛小组赛 A组加赛 TNC vs Newbee
2018/04/03 DOTA
[43:24]VG vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
python链接Oracle数据库的方法
2015/06/28 Python
python中print的不换行即时输出的快速解决方法
2016/07/20 Python
利用Python将时间或时间间隔转为ISO 8601格式方法示例
2017/09/05 Python
python将list转为matrix的方法
2018/12/12 Python
妙用itchat! python实现久坐提醒功能
2019/11/25 Python
python opencv图片编码为h264文件的实例
2019/12/12 Python
python3中编码获取网页的实例方法
2020/11/16 Python
html5 Canvas画图教程(5)—canvas里画曲线之arc方法
2013/01/09 HTML / CSS
在HTML5 Canvas中放入图片和保存为图片的方法
2014/05/03 HTML / CSS
Foot Locker意大利官网:全球领先的运动鞋和服装零售商
2017/05/30 全球购物
奥地利购买珠宝和手表网站:ELLA JUWELEN
2019/09/03 全球购物
.NET程序员的几道面试题
2012/06/01 面试题
WEB控件及HTML服务端控件能否调用客户端方法?如果能,请解释如何调用?
2015/08/25 面试题
《小草和大树》教学反思
2014/02/16 职场文书
《美丽的丹顶鹤》教学反思
2014/04/22 职场文书
国旗下演讲稿
2014/05/08 职场文书
知识竞赛拉拉队口号
2014/06/16 职场文书
优秀应届生求职信
2014/06/16 职场文书
森林防火标语
2014/06/23 职场文书
Flask response响应的具体使用
2021/07/15 Python