yii2 速率yii2 限制访问 一定要在用户认证后才能用么

Yii2框架RESTful API 格式化响应,授权认证和速率限制三部分详解
之前写过一篇Yii2框架制作RESTful风格的API快速入门教程,今天接着来探究一下Yii2 RESTful的格式化响应,授权认证和速率限制三个部分
一、目录结构
先列出需要改动的文件。目录如下:
├─ 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\
use yii\rest\ActiveC
use yii\web\R
class BookController extends ActiveController
public $modelClass = 'frontend\models\Book';
public function behaviors() {
$behaviors = parent::behaviors();
$behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
返回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\
use yii\rest\ActiveC
use yii\web\R
use yii\filters\auth\CompositeA
use yii\filters\auth\QueryParamA
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;
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', '', '', '123', '4', '');
在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\
use yii\rest\ActiveC
use yii\web\R
use yii\filters\auth\CompositeA
use yii\filters\auth\QueryParamA
use yii\filters\RateL
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;
2.在user表中使用两列来记录容差和时间戳信息。为了提高性能,可以考虑使用缓存或NoSQL存储这些信息。
修改common/models/User.php,加入红色标记代码:
namespace common\
use yii\base\NotSupportedE
use yii\behaviors\TimestampB
use yii\db\ActiveR
use yii\web\IdentityI
use yii\filters\RateLimitI
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 = $
$this-&allowance_updated_at = $
$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 格式化响应,授权认证和速率限制三部分详解 ,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网管之家网站的支持!
顶一下(0) 踩一下(0)
热门标签:yii2 restful web服务[速率限制]_PHP教程_ThinkSAAS
yii2 restful web服务[速率限制]
yii2 restful web服务[速率限制]
内容来源: 网络
PHP开发框架
开发工具/编程工具
服务器环境
ThinkSAAS商业授权:
ThinkSAAS为用户提供有偿个性定制开发服务
ThinkSAAS将为商业授权用户提供二次开发指导和技术支持
让ThinkSAAS更好,把建议拿来。
开发客服微信您的位置:
& RESTful Web 服务
为防止滥用,你应该考虑增加速率限制到您的API。
例如,您可以限制每个用户的API的使用是在10分钟内最多100次的API调用。
如果一个用户同一个时间段内太多的请求被接收, 将返回响应状态代码 429 (这意味着过多的请求)。
要启用速率限制, yii\web\User::identityClass 应该实现 yii\filters\RateLimitInterface.
这个接口需要实现以下三个方法:
getRateLimit(): 返回允许的请求的最大数目及时间,例如,[100, 600] 表示在600秒内最多100次的API调用。
loadAllowance(): 返回剩余的允许的请求和相应的UNIX时间戳数
当最后一次速率限制检查时。
saveAllowance(): 保存允许剩余的请求数和当前的UNIX时间戳。
你可以在user表中使用两列来记录容差和时间戳信息。
loadAllowance() 和 saveAllowance() 可以通过实现对符合当前身份验证的用户
的这两列值的读和保存。为了提高性能,你也可以
考虑使用缓存或NoSQL存储这些信息。
一旦 identity 实现所需的接口, Yii 会自动使用 yii\filters\RateLimiter
为 yii\rest\Controller 配置一个行为过滤器来执行速率限制检查。 如果速度超出限制
该速率限制器将抛出一个 yii\web\TooManyRequestsHttpException。 你可以在你的 REST
控制器类里配置速率限制,
public function behaviors()
$behaviors = parent::behaviors();
$behaviors['rateLimiter']['enableRateLimitHeaders'] =
当速率限制被激活,默认情况下每个响应将包含以下HTTP头发送
目前的速率限制信息:
X-Rate-Limit-Limit: 同一个时间段所允许的请求的最大数目;
X-Rate-Limit-Remaining: 在当前时间段内剩余的请求的数量;
X-Rate-Limit-Reset: 为了得到最大请求数所等待的秒数。
你可以禁用这些头信息通过配置 yii\filters\RateLimiter::enableRateLimitHeaders 为false,
就像在上面的代码示例所示。
本站部份内容来源自网络,文字、素材、图片版权属于原作者,本站转载素材仅供大家欣赏和分享,切勿做为商业目的使用。如有侵权请联系:QQ
Copyright (C)
All Rights Reserved.
网站备案号:为防止滥用,你应该考虑增加速率限制到您的API。 例如,您可以限制每个用户的API的使用是在10分钟内100次的API调用。 如果一个用户同一个时间段内太多的请求被接收, 将返回响应状态代码 429 (这意味着过多的请求)。
要启用速率限制, [[yii\web\User::identityClass|user identity ]] 应该实现 [[yii\filters\RateLimitInterface]]. 这个需要实现以下三个方法:
getRateLimit(): 返回允许的请求的最大数目及时间,例如,[100, 600]?表示在600秒内最多100次的API调用。
loadAllowance(): 返回剩余的允许的请求和相应的UNIX时间戳数 当最后一次速率限制检查时。
saveAllowance(): 保存允许剩余的请求数和当前的UNIX时间戳。
你可以在user表中使用两列来记录容差和时间戳信息。?loadAllowance()?和?saveAllowance()?可以通过实现对符合当前身份验证的用户 的这两列值的读和保存。为了提高性能,你也可以 考虑使用缓存或NoSQL存储这些信息。
一旦 identity 实现所需的接口, Yii 会自动使用 [[yii\filters\RateLimiter]] 为 [[yii\rest\Controller]] 配置一个行为过滤器来执行速率限制检查。 如果速度超出限制 该速率限制器将抛出一个 [[yii\web\TooManyRequestsHttpException]]。 你可以在你的 REST 控制器类里配置速率限制,
behaviors()
$behaviors = parent::behaviors();
$behaviors['rateLimiter']['enableRateLimitHeaders'] = false;
return $behaviors;
当速率限制被激活,默认情况下每个响应将包含以下头发送 目前的速率限制信息:
X-Rate-Limit-Limit: 同一个时间段所允许的请求的最大数目;
X-Rate-Limit-Remaining: 在当前时间段内剩余的请求的数量;
X-Rate-Limit-Reset: 为了得到最大请求数所等待的秒数。
你可以禁用这些头信息通过配置 [[yii\filters\RateLimiter::enableRateLimitHeaders]] 为false, 就像在上面的代码示例所示。Yii2中cookie的使用-为什么yii2 cookie使用起来会失效_商业生活网
Yii2中cookie的使用
为什么yii2 cookie使用起来会失效
myisam_recover = 64K#允许的GROUP_CONCAT()函数结果的最大长度
transaction_isolation = REPEATABLE-READ
innodb_file_per_table
相关问题与答案
Yii2.0中的COOKIE和SESSION用法
Yii2的Cookie主要是通过yii/web/Request和yii/web/Response进行操作的 ,通过/Yii::$app-&response-&getCookies()-&add()添加Cookie,通过/Yii::$app-&request-&cookies读取Cookie.
1)添加一个Cookie
//第一种方法
$cookie = new /yii/web/Cookie();
$cookie -& name = 'smister';//cookie的名称
$cookie -& expire = time() + 3600; //存活的时间
$cookie -& httpOnly = //无法通过js读取cookie
$cookie -& value = 'cookieValue'; //cookie的值
/Yii::$app-&response-&getCookies()-&add($cookie);
//第二种方法
$cookie = new /yii/web/Cookie([
‘name' =& ‘smister',
‘expire' =& time() + 3600,
‘httpOnly ' =& true,
‘value' =& ‘cookieValue'
/Yii::$app-&response-&getCookies()-&add($cookie);
2) 读取一个Cookie
$cookie = /Yii::$app-&request-&
//返回一个/yii/web/Cookie对象
$cookie-&get(‘smister');
//直接返回Cookie的值
$cookie-&getValue(‘smister'); //$cookie[‘smister'] 其实这样也是可以读取的
//判断一个Cookie是否存在
$cookie-&has(‘smister');
//读取Cookie的总数
$cookie-&count();//$cookie-&getCount();跟count一样
3) 删除Cookie
$cookie = Yii::$app-&request-&cookies-&get(‘smister');
//移除一个Cookie对象
/Yii::$app-&response-&getCookies()-&remove($cookie);
//移除所有Cookie,目前好像不太好使
/Yii::$app-&response-&getCookies()-&removeAll();
对Cookie进行增删改时调用的response , 对Cookie读取时使用的是Request
2、Session
Yii2的Session比较简单 ,直接通过/Yii::$app-&session进行操作就好了
1) 添加一个session
$session = /Yii::$app-&
$session-&set('smister_name' , 'myname');
$session-&set('smister_array' ,[1,2,3]);
2) 读取一个session
$session = /Yii::$app-&
//读取一个Session
$session-&get('smister_name);
3) 删除Session
$session = /Yii::$app-&
//删除一个session
$session-&remove(‘smister_name');
//删除所有session
$session-&removeAll();
以上所述是小编给大家介绍的Yii2.0中的COOKIE和SESSION用法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
解析PHP的Yii框架中cookie和session功能的相关操作
和 请求 和 响应类似, 默认可通过为yii\web\Session 实例的session 应用组件 来访问sessions。
开启和关闭 Sessions
可使用以下代码来开启和关闭session。
$session = Yii::$app-&
// 检查session是否开启
if ($session-&isActive) ...
// 开启session
$session-&open();
// 关闭session
$session-&close();
// 销毁session中所有已注册的数据
$session-&destroy();
多次调用yii\web\Session::open() 和yii\web\Session::close() 方法并不会产生错误, 因为方法内部会先检查session是否已经开启。
访问Session数据
To access the data stored in session, you can do the following: 可使用如下方式访问session中的数据:
$session = Yii::$app-&
// 获取session中的变量值,以下用法是相同的:
$language = $session-&get('language');
$language = $session['language'];
$language = isset($_SESSION['language']) ? $_SESSION['language'] :
// 设置一个session变量,以下用法是相同的:
$session-&set('language', 'en-US');
$session['language'] = 'en-US';
$_SESSION['language'] = 'en-US';
// 删除一个session变量,以下用法是相同的:
$session-&remove('language');
unset($session['language']);
unset($_SESSION['language']);
// 检查session变量是否已存在,以下用法是相同的:
if ($session-&has('language')) ...
if (isset($session['language'])) ...
if (isset($_SESSION['language'])) ...
// 遍历所有session变量,以下用法是相同的:
foreach ($session as $name =& $value) ...
foreach ($_SESSION as $name =& $value) ...
补充: 当使用session组件访问session数据时候,如果session没有开启会自动开启, 这和通过$_SESSION不同,$_SESSION要求先执行session_start()。
当session数据为数组时,session组件会限制你直接修改数据中的单元项,例如:
$session = Yii::$app-&
// 如下代码不会生效
$session['captcha']['number'] = 5;
$session['captcha']['lifetime'] = 3600;
// 如下代码会生效:
$session['captcha'] = [
'number' =& 5,
'lifetime' =& 3600,
// 如下代码也会生效:
echo $session['captcha']['lifetime'];
可使用以下任意一个变通方法来解决这个问题:
$session = Yii::$app-&
// 直接使用$_SESSION (确保Yii::$app-&session-&open() 已经调用)
$_SESSION['captcha']['number'] = 5;
$_SESSION['captcha']['lifetime'] = 3600;
// 先获取session数据到一个数组,修改数组的值,然后保存数组到session中
$captcha = $session['captcha'];
$captcha['number'] = 5;
$captcha['lifetime'] = 3600;
$session['captcha'] = $
// 使用ArrayObject 数组对象代替数组
$session['captcha'] = new \ArrayO
$session['captcha']['number'] = 5;
$session['captcha']['lifetime'] = 3600;
// 使用带通用前缀的键来存储数组
$session['captcha.number'] = 5;
$session['captcha.lifetime'] = 3600;
为更好的性能和可读性,推荐最后一种方案,也就是不用存储session变量为数组, 而是将每个数组项变成有相同键前缀的session变量。
自定义Session存储
yii\web\Session 类默认存储session数据为文件到服务器上,Yii提供以下session类实现不同的session存储方式:
yii\web\DbSession: 存储session数据在数据表中
yii\web\CacheSession: 存储session数据到缓存中,缓存和配置中的缓存组件相关
yii\redis\Session: 存储session数据到以redis 作为存储媒介中
yii\mongodb\Session: 存储session数据到MongoDB.
所有这些session类支持相同的API方法集,因此,切换到不同的session存储介质不需要修改项目使用session的代码。
注意: 如果通过$_SESSION访问使用自定义存储介质的session,需要确保session已经用yii\web\Session::open() 开启, 这是因为在该方法中注册自定义session存储处理器。
学习如何配置和使用这些组件类请参考它们的API文档,如下为一个示例 显示如何在应用配置中配置yii\web\DbSession将数据表作为session存储介质。
'components' =& [
'session' =& [
'class' =& 'yii\web\DbSession',
// 'db' =& 'mydb', // 数据库连接的应用组件ID,默认为'db'.
// 'sessionTable' =& 'my_session', // session 数据表名,默认为'session'.
也需要创建如下数据库表来存储session数据:
CREATE TABLE session
id CHAR(40) NOT NULL PRIMARY KEY,
expire INTEGER,
其中'BLOB' 对应你选择的数据库管理系统的BLOB-type类型,以下一些常用数据库管理系统的BLOB类型:
MySQL: LONGBLOB
PostgreSQL: BYTEA
MSSQL: BLOB
注意: 根据php.ini 设置的 session.hash_function,你需要调整id列的长度, 例如,如果session.hash_function=sha256 ,应使用长度为64而不是40的char类型。
Flash 数据
Flash数据是一种特别的session数据,它一旦在某个请求中设置后,只会在下次请求中有效,然后该数据就会自动被删除。 常用于实现只需显示给终端用户一次的信息,如用户提交一个表单后显示确认信息。
可通过session应用组件设置或访问session,例如:
$session = Yii::$app-&
// 请求 #1
// 设置一个名为"postDeleted" flash 信息
$session-&setFlash('postDeleted', 'You have successfully deleted your post.');
// 请求 #2
// 显示名为"postDeleted" flash 信息
echo $session-&getFlash('postDeleted');
// 请求 #3
// $result 为 false,因为flash信息已被自动删除
$result = $session-&hasFlash('postDeleted');
和普通session数据类似,可将任意数据存储为flash数据。
当调用yii\web\Session::setFlash()时, 会自动覆盖相同名的已存在的任何数据, 为将数据追加到已存在的相同名flash中,可改为调用yii\web\Session::addFlash()。 例如:
$session = Yii::$app-&
// 请求 #1
// 在名称为"alerts"的flash信息增加数据
$session-&addFlash('alerts', 'You have successfully deleted your post.');
$session-&addFlash('alerts', 'You have successfully added a new friend.');
$session-&addFlash('alerts', 'You are promoted.');
// 请求 #2
// $alerts 为名为'alerts'的flash信息,为数组格式
$alerts = $session-&getFlash('alerts');
注意: 不要在相同名称的flash数据中使用yii\web\Session::setFlash() 的同时也使用yii\web\Session::addFlash(), 因为后一个防范会自动将flash信息转换为数组以使新的flash数据可追加进来,因此, 当你调用yii\web\Session::getFlash()时,会发现有时获取到一个数组,有时获取到一个字符串, 取决于你调用这两个方法的顺序。
Yii使用 yii\web\Cookie对象来代表每个cookie,yii\web\Request 和 yii\web\Response 通过名为'cookies'的属性维护一个cookie集合,前者的cookie 集合代表请求提交的cookies, 后者的cookie集合表示发送给用户的cookies。
读取 Cookies
当前请求的cookie信息可通过如下代码获取:
// 从 "request"组件中获取cookie集合(yii\web\CookieCollection)
$cookies = Yii::$app-&request-&
// 获取名为 "language" cookie 的值,如果不存在,返回默认值"en"
$language = $cookies-&getValue('language', 'en');
// 另一种方式获取名为 "language" cookie 的值
if (($cookie = $cookies-&get('language')) !== null) {
$language = $cookie-&
// 可将 $cookies当作数组使用
if (isset($cookies['language'])) {
$language = $cookies['language']-&
// 判断是否存在名为"language" 的 cookie
if ($cookies-&has('language')) ...
if (isset($cookies['language'])) ...
发送 Cookies
You can send cookies to end users using the following code: 可使用如下代码发送cookie到终端用户:
// 从"response"组件中获取cookie 集合(yii\web\CookieCollection)
$cookies = Yii::$app-&response-&
// 在要发送的响应中添加一个新的cookie
$cookies-&add(new \yii\web\Cookie([
'name' =& 'language',
'value' =& 'zh-CN',
// 删除一个cookie
$cookies-&remove('language');
// 等同于以下删除代码
unset($cookies['language']);
除了上述例子定义的 yii\web\Cookie::name 和 yii\web\Cookie::value 属性 yii\web\Cookie 类也定义了其他属性来实现cookie的各种信息,如 yii\web\Cookie::domain, yii\web\Cookie::expire 可配置这些属性到cookie中并添加到响应的cookie集合中。
注意: 为安全起见yii\web\Cookie::httpOnly 被设置为true,这可减少客户端脚本访问受保护cookie(如果浏览器支持)的风险, 更多详情可阅读 httpOnly wiki article for more details.
Cookie验证
在上两节中,当通过request 和 response 组件读取和发送cookie时,你会喜欢扩展的cookie验证的保障安全功能,它能 使cookie不被客户端修改。该功能通过给每个cookie签发一个哈希字符串来告知服务端cookie是否在客户端被修改, 如果被修改,通过request组件的yii\web\Request::cookiescookie集合访问不到该cookie。
注意: Cookie验证只保护cookie值被修改,如果一个cookie验证失败,仍然可以通过$_COOKIE来访问该cookie, 因为这是第三方库对未通过cookie验证自定义的操作方式。
Cookie验证默认启用,可以设置yii\web\Request::enableCookieValidation属性为false来禁用它,尽管如此,我们强烈建议启用它。
注意: 直接通过$_COOKIE 和 setcookie() 读取和发送的Cookie不会被验证。
当使用cookie验证,必须指定yii\web\Request::cookieValidationKey,它是用来生成s上述的哈希值, 可通过在应用配置中配置request 组件。
'components' =& [
'request' =& [
'cookieValidationKey' =& 'fill in a secret key here',
补充: yii\web\Request::cookieValidationKey 对你的应用安全很重要, 应只被你信任的人知晓,请不要将它放入版本控制中。
Yii2中cookie用法示例分析
本文实例讲述了Yii2中cookie用法。分享给大家供大家参考,具体如下:
//设置方法
$cookie = new Cookie([
'name' =& 'cookie_monster',
'value' =& 'Me want cookie!',
'expire' =& time() + 86400 * 365,
\Yii::$app-&getResponse()-&getCookies()-&add($cookie);
//读取方法
$value = \Yii::$app-&getRequest()-&getCookies()-&getValue('my_cookie');
//给cookie加域名
$cookie = new Cookie([
'name' =& 'cookie_monster',
'value' =& 'Me want cookie everywhere!',
'expire' =& time() + 86400 * 365,
'domain' =& '.' // &&&=== HERE
\Yii::$app-&getResponse()-&getCookies()-&add($cookie);
//设置登录cookie
$config = [
'components' =& [
'user' =& [
'class' =& 'yii\web\User',
'identityClass' =& 'app\models\User',
'enableAutoLogin' =& true,
'loginUrl' =& '/user/login',
'identityCookie' =& [ // &---- here!
'name' =& '_identity',
'httpOnly' =& true,
'domain' =& '.',
'request' =& [
'cookieValidationKey' =& 'your_validation_key'
'session' =& [
'cookieParams' =& [
'domain' =& '.',
'httpOnly' =& true,
//只给批定目录配置cookie
$config = [
'components' =& [
'session' =& [
'name' =& 'admin_session',
'cookieParams' =& [
'httpOnly' =& true,
'path' =& '/admin',
更多关于Yii相关内容感兴趣的读者可查看本站专题:《Yii框架入门及常用技巧总结》、《php优秀开发框架总结》、《smarty模板入门基础教程》、《php面向对象程序设计入门教程》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。
Yii中的cookie的发送和读取
  //新创建的cookie会从本地传到服务器上,然后从服务器获取。
(1) cookie的发送
 $cookies = Yii::$app-&response-&
   // 在要发送的响应中添加一个新的cookie
  eg:往cookies中添加用户名和密码
  $cookies-&add(new Cookie(['name'=&'username', 'value'=&$username,]));
  $cookies-&add(new Cookie(['name'=&'password', 'value'=&$password,]));
  //删除一个cookie
  $cookies-&remove('username');
  //相当于
  unset($cookies['username']);
(2)cookie的获取
$cookies = Yii::$app-&request-&
  // 获取名为 "username" cookie 的值,如果不存在,返回默认值"en"
  $username = $cookies-&getValue('username', 'en');
  // 另一种方式获取名为 "username" cookie 的值
  if (($cookie = $cookies-&getValue('username')) !== null) {
    $username = $cookie-&
// 判断是否存在名为username的cookie
if (isset($cookies['username'])) {
$username= $cookies['username']-&  ...
}if($cookies-&has('username')){}
以上所述是小编给大家介绍的Yii中的cookie的发送和读取 ,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
yii操作cookie实例简介
yii对cookie的操作常见的主要有以下几种:
1.设置cookie:
$cookie = new CHttpCookie('mycookie','this is my cookie');
$cookie-&expire = time()+60*60*24*30; //有限期30天
Yii::app()-&request-&cookies['mycookie']=$
2.读取cookie:
$cookie = Yii::app()-&request-&getCookies();
echo $cookie['mycookie']-&
3.销毁cookie:
$cookie = Yii::app()-&request-&getCookies();
unset($cookie[$name]);
在yii中新增一个用户验证的方法详解
1.为什么要新增一个用户验证:因为我要将网站后台和前台做在同一个yii的应用中.但是前台也包含有会员的管理中心.而这两个用户验证是完全不同的,所以需要两个不同登陆页面,要将用户信息保存在不同的cookie或session中.所以需要在一个应用中增加一个用户验证2.yii的用户验证:在自定义用户验证前,我们首先要弄清楚yii的验证和授权方式.为了验证一个用户,我们需要定义一个有验证逻辑的验证类.在yii中这个类需要实现IUserIdentity接口,不同的类就可以实现不同的验证方 法.网站登陆一般需要验证的就是用户名和密码,yii提供了CUserIdentity类,这个类一般用于验证用户名和密码的类.继承后我们需要重写其中 的authenticate()方法来实现我们自己的验证方法.具体代码如下:Php代码复制代码 代码如下:class UserIdentity extends CUserIdentity& {& &&& private $_& &&& public function authenticate()& &&& {& &&&&&&& $record=User::model()-&findByAttributes(array('username'=&$this-&username));& &&&&&&& if($record===null)& &&&&&&&&&&& $this-&errorCode=self::ERROR_USERNAME_INVALID;& &&&&&&& else if($record-&password!==md5($this-&password))& &&&&&&&&&&& $this-&errorCode=self::ERROR_PASSWORD_INVALID;& &&&&&&& else &&&&&&& {& &&&&&&&&&&& $this-&_id=$record-&& &&&&&&&&&&& $this-&setState('title', $record-&title);& &&&&&&&&&&& $this-&errorCode=self::ERROR_NONE;& &&&&&&& }& &&&&&&& return !$this-&errorC& &&& }& &&& public function getId()& &&& {& &&&&&&& return $this-&_& &&& }& } 在用户登陆时则调用如下代码:Php代码复制代码 代码如下:// 使用提供的用户名和密码登录用户& $identity=new UserIdentity($username,$password);& if($identity-&authenticate())& &&& Yii::app()-&user-&login($identity);& else &&& echo $identity-&errorM 用户退出时,则调用如下代码:Php代码复制代码 代码如下:// 注销当前用户& Yii::app()-&user-&logout(); &其中的user是yii的一个components.需要在protected/config/main.php中定义Php代码复制代码 代码如下:'user'=&array(& &&& // enable cookie-based authentication& &&& 'allowAutoLogin'=&true,& &&&&&&& 'loginUrl' =& array('site/login'),& ), 这里我们没有指定user的类名.因为在yii中默认user为CWebUser类的实例.我 们现在已经实现了用户的登陆验证和退出.但是现在无论是否登陆,用户都能访问所有的action,所以下一步我们要对用户访问进行授权.在yii里是通过 Access Control Filter即访问控制过滤器来实现用户授权的.我们看一下一个简单的带有访问控制的Controller:Php代码复制代码 代码如下:class AdminDefaultController extends CController& {&& &&& public function filters()& &&&&&&& {& &&&&&&&&&&& return array('accessControl');& &&&&&&& }& &&&&&&& public function accessRules()& &&&&&&& {& &&&&&&&&&&& return array(& &&&&&&&&&&&&&&& array(& &&&&&&&&&&&&&&&&&&& 'allow',& &&&&&&&&&&&&&&&&&&& 'users' =& array('@'),& &&&&&&&&&&&&&&& ),& &&&&&&&&&&&&&&& array(& &&&&&&&&&&&&&&&&&&& 'deny',& &&&&&&&&&&&&&&&&&&& 'users' =& array('*')& &&&&&&&&&&&&&&& ),& &&&&&&&&&&& );& &&&&&&& }& } 我们在filters方法中设置具体的filter.我们可以看到在filters方法返回的array里有accessControl参数,在CController类中有一个filterAccessControl方法:Php代码复制代码 代码如下:public function filterAccessControl($filterChain)& {& &&& $filter=new CAccessControlF& &&& $filter-&setRules($this-&accessRules());& &&& $filter-&filter($filterChain);& } 在里面新建了一个CAccessControlFilter实例,并且在setRules时传入了accessRules()方法返回的参数.$filter-&filter($filterChain)则是继续调用其它filter.而所有具体的授权规则则是定义在accessRules中:Php代码复制代码 代码如下:public function accessRules()& &&& {& &&&&&&& return array(& &&&&&&&&&&& array('deny',& &&&&&&&&&&&&&&& 'actions'=&array('create', 'edit'),& &&&&&&&&&&&&&&& 'users'=&array('?'),& &&&&&&&&&&& ),& &&&&&&&&&&& array('allow',& &&&&&&&&&&&&&&& 'actions'=&array('delete'),& &&&&&&&&&&&&&&& 'roles'=&array('admin'),& &&&&&&&&&&& ),& &&&&&&&&&&& array('deny',& &&&&&&&&&&&&&&& 'actions'=&array('delete'),& &&&&&&&&&&&&&&& 'users'=&array('*'),& &&&&&&&&&&& ),& &&&&&&& );& &&& } 具体规则参见yii的手册. 3.新增一个验证体系:首先我们从CWebUser继承一个CAdminUser:Php代码复制代码 代码如下:class CAdminWebUser extends CWebUser& {& &&& public $loginUrl = array('admin/admin/login');& } 我们需要把他放置到components中如果是全局应用则通过protected/config/main.php的components小节:Php代码复制代码 代码如下:'user'=&array(& &&& // enable cookie-based authentication& &&&&&&& 'class' =& 'CAdminUser',& &&& 'allowAutoLogin'=&true,& &&&&&& 'loginUrl' =& array('site/login'),& ), 如果是在modules中则在模块类的init方法中添加如下代码:Php代码复制代码 代码如下:$this-&setComponents(array(& &&&&&& 'adminUser' =& array(& &&&&&&&&&&&&&&& 'class' =& 'CAdminWebUser',& &&&&&&&&&&&&&&& 'allowAutoLogin' =& false,& &&&&&&& )& )); 最后调用方式Php代码复制代码 代码如下://全局应用& Yii::app()-&getComponent('adminUser');& //在模块中& Yii::app()-&controller-&module-&getComponent('adminUser'); 但仅仅这样还不够,我们还需要修改Controller的filter,我们需要自定义一个filter,来实现另一个用户的验证和授权第一步自定义一个filter:Php代码复制代码 代码如下:class CAdminAccessControlFilter extends CAccessControlFilter& {& &&& protected function preFilter($filterChain)& &&& {& &&&&&&& $app=Yii::app();& &&&&&&& $request=$app-&getRequest();& &&&&&&& $user = Yii::app()-&controller-&module-&getComponent('adminUser');& &&&&&&& $verb=$request-&getRequestType();& &&&&&&& $ip=$request-&getUserHostAddress();& &&&&&&& foreach($this-&getRules() as $rule)& &&&&&&& {& &&&&&&&&&&& if(($allow=$rule-&isUserAllowed($user,$filterChain-&controller,$filterChain-&action,$ip,$verb))&0) // allowed& &&&&&&&&&&&&&&&& &&&&&&&&&&& else if($allow&0) // denied& &&&&&&&&&&& {& &&&&&&&&&&&&&&& $this-&accessDenied($user);& &&&&&&&&&&&&&&&& &&&&&&&&&&& }& &&&&&&& }& &&&&&&&& &&& }& } 再重写CController类的filterAccessController方法Php代码复制代码 代码如下:public function filterAccessControl($filterChain)& {& &&& $filter = new CAdminAccessControlFilter();& &&& $filter-&setRules($this-&accessRules());& &&& $filter-&filter($filterChain);& }& //在这里我们使用自定义的filter类替换了原来的filter OK,到这里我们就可以在此Controller的accessRules()中指定adminUser的授权了
YII Framework框架教程之安全方案详解
本文讲述了YII Framework框架的安全方案。分享给大家供大家参考,具体如下:
web应用的安全问题是很重要的,在“黑客”盛行的年代,你的网站可能明天都遭受着攻击,为了从某种程度上防止被攻击,YII提供了防止攻击的几种解决方案。当然这里讲的安全是片面的,但是值得一看。
官方提供的解决方案有:如下
1. 跨站脚本攻击的防范
跨站脚本攻击(简称 XSS),即web应用从用户收集用户数据。 攻击者常常向易受攻击的web应用注入JavaScript,VBScript,ActiveX,HTML或 Flash来迷惑访问者以收集访问者的信息。 举个例子,一个未经良好设计的论坛系统可能不经检查就显示用户所输入的内容。 攻击者可以在帖子内容中注入一段恶意的JavaScript代码。 这样,当其他访客在阅读这个帖子的时候,这些JavaScript代码就可以在访客的电脑上运行了。
一个防范XSS攻击的最重要的措施之一就是:在显示用户输入的内容之前进行内容检查。 比如,你可以对内容中的HTML进行转义处理。但是在某些情况下这种方法就不可取了,因为这种方法禁用了所有的HTML标签。
Yii集成了HTMLPurifier并且为开发者提供了一个很有用的组件CHtmlPurifier, 这个组件封装了HTMLPurifier类。它可以将通过有效的审查、安全和白名单功能来把所审核的内容中的所有的恶意代码清除掉,并且确保过滤之后的内容过滤符合标准。
CHtmlPurifier组件可以作为一个widget或者filter来使用。 当作为一个widget来使用的时候,CHtmlPurifier可以对在视图中显示的内容进行安全过滤。 以下是代码示例:
&?php $this-&beginWidget('CHtmlPurifier'); ?&
//...这里显示用户输入的内容...
&?php $this-&endWidget(); ?&
2. 跨站请求伪造攻击的防范
跨站请求伪造(简称CSRF)攻击,即攻击者在用户浏览器在访问恶意网站的时候,让用户的浏览器向一个受信任的网站发起攻击者指定的请求。 举个例子,一个恶意网站有一个图片,这个图片的src地址指向一个银行网站:http://bank.example/withdraw?transfer=10000&to=someone。 如果用户在登陆银行的网站之后访问了这个恶意网页,那么用户的浏览器会向银行网站发送一个指令,这个指令的内容可能是“向攻击者的帐号转账10000元”。 跨站攻击方式利用用户信任的某个特定网站,而CSRF攻击正相反,它利用用户在某个网站中的特定用户身份。
要防范CSRF攻击,必须谨记一条:GET请求只允许检索数据而不能修改服务器上的任何数据。 而POST请求应当含有一些可以被服务器识别的随机数值,用来保证表单数据的来源和运行结果发送的去向是相同的。
Yii实现了一个CSRF防范机制,用来帮助防范基于POST的攻击。 这个机制的核心就是在cookie中设定一个随机数据,然后把它同表单提交的POST数据中的相应值进行比较。
默认情况下,CSRF防范是禁用的。如果你要启用它,可以编辑应用配置 中的组件中的CHttpRequest部分。
代码示例:
return array(
'components'=&array(
'request'=&array(
'enableCsrfValidation'=&true,
要显示一个表单,请使用CHtml::form而不要自己写HTML代码。因为CHtml::form可以自动地在表单中嵌入一个隐藏项,这个隐藏项储存着验证所需的随机数据,这些数据可在表单提交的时候发送到服务器进行验证。
3. Cookie攻击的防范
保护cookie免受攻击是非常重要的。因为session ID通常存储在Cookie中。 如果攻击者窃取到了一个有效的session ID,他就可以使用这个session ID对应的session信息。
这里有几条防范对策:
您可以使用SSL来产生一个安全通道,并且只通过HTTPS连接来传送验证cookie。这样攻击者是无法解密所传送的cookie的。
设置cookie的过期时间,对所有的cookie和seesion令牌也这样做。这样可以减少被攻击的机会。
防范跨站代码攻击,因为它可以在用户的浏览器触发任意代码,这些代码可能会泄露用户的cookie。
在cookie有变动的时候验证cookie的内容。
Yii实现了一个cookie验证机制,可以防止cookie被修改。启用之后可以对cookie的值进行HMAC检查。
Cookie验证在默认情况下是禁用的。如果你要启用它,可以编辑应用配置 中的组件中的CHttpRequest部分。
代码示例:
return array(
'components'=&array(
'request'=&array(
'enableCookieValidation'=&true,
一定要使用经过Yii验证过的cookie数据。使用Yii内置的cookies组件来进行cookie操作,不要使用$_COOKIES。
// 检索一个名为$name的cookie值
$cookie=Yii::app()-&request-&cookies[$name];
$value=$cookie-&
// 设置一个cookie
$cookie=new CHttpCookie($name,$value);
Yii::app()-&request-&cookies[$name]=$
更多关于Yii相关内容感兴趣的读者可查看本站专题:《Yii框架入门及常用技巧总结》、《php优秀开发框架总结》、《smarty模板入门基础教程》、《php日期与时间用法总结》、《php面向对象程序设计入门教程》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。
全面解读PHP的Yii框架中的日志功能
Yii页面级日志开启
在 Main.php中 log段添加、
下面显示页面日志 array( 'class'=&'CWebLogRoute', 'levels'=&'trace', //级别为trace 'categories'=&'system.db.*' //只显示关于数据库信息,包括数据库连接,数据库执行语句 ),
完整如下:
'log'=&array(
'class'=&'CLogRouter',
'routes'=&array(
'class'=&'CFileLogRoute',
'levels'=&'error, warning',
// 下面显示页面日志
'class'=&'CWebLogRoute',
'levels'=&'trace',
//级别为trace
'categories'=&'system.db.*' //只显示关于数据库信息,包括数据库连接,数据库执行语句
// uncomment the following to show log messages on web pages
'class'=&'CWebLogRoute',
扩展 Yii2 自带的日志组件
: forecho &&
* createTime :
* description:
namespace common\
use yii\helpers\FileH
class FileTarget extends \yii\log\FileTarget
* @var bool 是否启用日志前缀 (@app/runtime/logs/error/_app.log)
public $enableDatePrefix =
* @var bool 启用日志等级目录
public $enableCategoryDir =
private $_logFilePath = '';
public function init()
if ($this-&logFile === null) {
$this-&logFile = Yii::$app-&getRuntimePath() . '/logs/app.log';
$this-&logFile = Yii::getAlias($this-&logFile);
$this-&_logFilePath = dirname($this-&logFile);
// 启用日志前缀
if ($this-&enableDatePrefix) {
$filename = basename($this-&logFile);
$this-&logFile = $this-&_logFilePath . '/' . date('Ymd') . '_' . $
if (!is_dir($this-&_logFilePath)) {
FileHelper::createDirectory($this-&_logFilePath, $this-&dirMode, true);
if ($this-&maxLogFiles & 1) {
$this-&maxLogFiles = 1;
if ($this-&maxFileSize & 1) {
$this-&maxFileSize = 1;
在配置文件中这样使用:
'components' =& [
'log' =& [
'traceLevel' =& YII_DEBUG ? 3 : 0,
'targets' =& [
* 错误级别日志:当某些需要立马解决的致命问题发生的时候,调用此方法记录相关信息。
* 使用方法:Yii::error()
'class' =& 'common\components\FileTarget',
// 日志等级
'levels' =& ['error'],
// 被收集记录的额外数据
'logVars' =& ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION','_SERVER'],
// 指定日志保存的文件名
'logFile' =& '@app/runtime/logs/error/app.log',
// 是否开启日志 (@app/runtime/logs/error/_app.log)
'enableDatePrefix' =& true,
'maxFileSize' =& 1024 * 1,
'maxLogFiles' =& 100,
* 警告级别日志:当某些期望之外的事情发生的时候,使用该方法。
* 使用方法:Yii::warning()
'class' =& 'common\components\FileTarget',
// 日志等级
'levels' =& ['warning'],
// 被收集记录的额外数据
'logVars' =& ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION','_SERVER'],
// 指定日志保存的文件名
'logFile' =& '@app/runtime/logs/warning/app.log',
// 是否开启日志 (@app/runtime/logs/warning/_app.log)
'enableDatePrefix' =& true,
'maxFileSize' =& 1024 * 1,
'maxLogFiles' =& 100,
* info 级别日志:在某些位置记录一些比较有用的信息的时候使用。
* 使用方法:Yii::info()
'class' =& 'common\components\FileTarget',
// 日志等级
'levels' =& ['info'],
// 被收集记录的额外数据
'logVars' =& ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION','_SERVER'],
// 指定日志保存的文件名
'logFile' =& '@app/runtime/logs/info/app.log',
// 是否开启日志 (@app/runtime/logs/info/_app.log)
'enableDatePrefix' =& true,
'maxFileSize' =& 1024 * 1,
'maxLogFiles' =& 100,
* trace 级别日志:记录关于某段代码运行的相关消息。主要是用于开发环境。
* 使用方法:Yii::trace()
'class' =& 'common\components\FileTarget',
// 日志等级
'levels' =& ['trace'],
// 被收集记录的额外数据
'logVars' =& ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION','_SERVER'],
// 指定日志保存的文件名
'logFile' =& '@app/runtime/logs/trace/app.log',
// 是否开启日志 (@app/runtime/logs/trace/_app.log)
'enableDatePrefix' =& true,
'maxFileSize' =& 1024 * 1,
'maxLogFiles' =& 100,
yii日志的逻辑
Yii使用层次的日志处理机制,即日志的收集与日志最终的处理(如显示、保存到文件、保存到数据数)是分离的。
日志信息的收集由CLogger(日志记录器)完成,而日志信息的分发处理,则在CLogRouter的调度(称为日志路由管理器)下,分发给处理对象(如CFileLogRoute以及logging目录下继承自CLogRoute的类, 称为日志处理器),经过反复阅读其源代码,我更是为Yii的设计思想所折服,如此的分层处理,使得其易于灵活扩展。
而日志信息有级别之分,如普通的info, profile, trace, warning, error级别,可以在日志路由中设置过虑条件,如设置CFileRoute的levels属性,即可只处理指定级别的日志信息。
如在程序中调用:
Yii::log($message,CLogger::LEVEL_ERROR,$category);
对应的流程可能如下:
生成CLogger实例
如果YII_DEBUG , YII_TRACE_LEVEL都已经定义为有效值,并且日志级别不是profile, 则产生调用回溯信息, 并追加到日志信息上。
调用CLogger:: log($msg,$level,$category) 收集日志,实际上这时日志并没有写入文件,仅仅是暂存于内存之中。
问题:日志是在何时被写入文件的?
经过反复跟踪,我发现在CLogRouter类的init方法中为Application对象的OnEndRequest事件绑定处理器CLogRouter::processLogs()。同时也给Yii::$_logger的onFlush事件绑定事件处理器CLogRouter::collectLogs方法,用于在Yii::log()中当日志消息量过多时,及时将日志刷新写入文件。代码如下:
* Initializes this application component.
* This method is required by the IApplicationComponent interface.
public function init(){
parent::init();
foreach($this-&_routes as $name=&$route) {
$route=Yii::createComponent($route);
$route-&init();
$this-&_routes[$name]=$
Yii::getLogger()-&attachEventHandler('onFlush',array($this,'collectLogs'));
Yii::app()-&attachEventHandler('onEndRequest',array($this,'processLogs'));}
而在CApplication::run()方法中定义了:
if($this-&hasEventHandler('onEndRequest')) {
$this-&onEndRequest(new CEvent($this));
到这里我们可以理解CLogger (Yii::$_logger)仅仅是将日志进行收集(记录到内容结构之中),然后在程序结束时,由$app对象调用CLogRouter的processLogs进行日志的处理。Yii支持日志多道路由,比如:同一份日志即可写入至文件,又可显示到页面上,甚至同时以电子邮件发送,更甚至同时记录到数据库中,这是由配置文件中的log:routes配置实现的,为log:routes配置多个元素,实现多个路由分发。日志信息的过滤,记录均是由最终的日志处理器处理。
日志处理器要完成的任务主要包含以下几点: 从CLogger中取得所有日志,并进行过滤(主要是levels, categories两项定义log:routes:levels/categories)
先进行过滤参考CFileLogRoute::collectLogs()中的逻辑:
$logs=$logger-&getLogs($this-&levels,$this-&categories); //执行过滤,只得到期望信息
日志过滤已经完成接下来就要对日志进行最终处理(如写入到文件,记录至数据库等)
CFileLogRoute::processLogs($logs);
但这个函数之中,有个小bug, 只判断日志目录是否可写,没有判断日志文件本身是否可写.CFileLogRoute实现了类似Linux的日志轮换功能(LogRoate), 并规定了日志文件的大小,考虑得很周到,很完善! 我也要向其学习并吸收其思想!
protected/config/main.php中的配置:
'preload'=&array('log'),
components =& array(
'log'=&array(
'class'=&'CLogRouter',
'routes'=&array(
'class'=&'CFileLogRoute',
'levels'=&'error, warning,trace',
定义log组件需要预先加载(实例化)。配置使用CLogRouter作为日志路由管理器,并设置了其日志路由处理器(routes属性)及其配置属性。而preload, log属性的定义,均要应用到CWebApplication对象上(请参阅CApplication::__construct中的configure调用, configure从CModule继承而来)。而在CWebApplication的构造函数中执行preloadComponents(),就创建了log对象(即CLogRouter的实例)。
创建并初始化一个组件时,实际上调用的是CModule::getComponent, 这个调用中使用YiiBase::createComponent创建组件对象,并再调用组件的init初始化之。
再阅读CLogRouter::init()过程,在这里有两个关键之处,一是创建日志路由处理器(即决定日志的最终处理方式:写入文件,邮件发送等等),二是给应用程序对象绑定onEndRequest事件处理CLogRouter::processLogs()。而在CApplication::run()确实有相关代码用于运行onEndRequest事件处理句柄:
if($this-&hasEventHandler('onEndRequest')) {
$this-&onEndRequest(new CEvent($this));
也就是说,日志的最终处理(比如写入文件,系统日志,发送邮件)是发生在应用程序运行完毕之后的。Yii使用事件机制,巧妙地实现了事件与处理句柄的关联。
也就是说,当应用程序运行完毕,将执行CLogRouter::processLogs,对日志进行处理,。CLogRouter被称之为日志路由管理器。每个日志路由处理器从CLooger对象中取得相应的日志(使用过滤机制),作最终处理。
具体而言Yii的日志系统,分为以下几个层次:
日志发送者,即程序中调用Yii::log($msg, $level, $category),将日志发送给CLogger对象
CLogger对象负责将日志记录暂存于内存之中程序运行结束后,log组件(日志路由管理器CLogRoute)的processLogs方法被激活执行,由其逐个调用日志路由器,作日志的最后处理。
更为详细的大致过程如下:
CApplication::__construct()中调用preloadComponents, 这导致log组件(CLogRoute)被实例化,并被调用init方法初始化。
log组件(CLogRoute)的init方法中,其是初始化日志路由,并给CApplication对象onEndRequest事件绑定处理流程processLogs。给CLooger组件的onFlush事件绑定处理流程collectLogs。
应用程序的其它部分通过调用Yii::log()向CLogger组件发送日志信息,CLogger组件将日志信息暂存到内存中。
CApplication执行完毕(run方法中),会激活onEndRequest事件,绑定的事件处理器processLogs被执行,日志被写入文件之中。 Yii的日志路由机制,给日志系统扩展带来了无限的灵活。并且其多道路由处理机制,可将同一份日志信息进行多种方式处理。
这里举出一个案例:发生error级别的数据库错误时,及时给相关维护人员发送电子邮件,并同时将这些日志记录到文件之中。规划思路,发送邮件和手机短信是两个不同的功能,Yii已经带了日志邮件发送组件(logging/CEmailLogRoute.php),但这个组件中却使用了php自带的mail函数,使用mail函数需要配置php.ini中的smtp主机,并且使用非验证发送方式,这种方式在目前的实际情况下已经完全不可使用。代替地我们需要使用带验证功能的smtp发送方式。在protected/components/目录下定义日志处理器类myEmailLogRoute,并让其继承自CEmailLogRoute,最主要的目的是重写CEmailLogRoute::sendEmail()方法& ,其中,SMTP的处理细节请自行完善(本文的重点是放在如何处理日志上,而不是发送邮件上)。
接下来,我们就可以定义日志路由处理,编辑protected/config/main.php, 在log组件的routes组件添加新的路由配置:
'log'=&array(
'class'=&'CLogRouter',
'routes'=&array(
'class'=&'CFileLogRoute',
'levels'=&'error, warning,trace',
'class' =& 'myEmailLogRoute',
'levels' =& 'error', #所有异常的错误级别均为error,
'categories' =& 'exception.CDbException', #数据库产生错误时,均会产生CDbException异常。
'host' =& '',
'port' =& 25,
'user' =& 'jeff_yu',
'password' =& 'you password',
'timeout' =& 30,
'emails' =& 'jeff_', #日志接收人。
'sentFrom' =& 'jeff_',
经过以上处理,即可使之实现我们的目的,当然你可以根据自己的需要进一步扩展之。
Yii中实现处理前后台登录的新方法
本文实例讲述了Yii中实现处理前后台登录的新方法。分享给大家供大家参考,具体如下:
因为最近在做一个项目涉及到前后台登录问题,我是把后台作为一个模块(Module)来处理的。我看很多人放两个入口文件index.php和admin.php,然后分别指向前台和后台。这种方法固然很好,可以将前后台完全分离,但我总觉得这种方式有点牵强,这和两个应用啥区别?还不如做两个App用一个framework更好。而且Yii官方后台使用方法也是使用Module的方式。但是Moudle的方式有一个很头疼的问题,就是在使用Cwebuser登录时会出现前后台一起登录一起退出的问题,这显然是不合理的。我纠结了很久才找到下文即将介绍的方法,当然,很多也是参考别人的,自己稍作了改动。我一开始的做法是在后台登录时设置一个isadmin的session,然后再前台登录时注销这个session,这样做只能辨别是前台登录还是后台登录,但做不到前后台一起登录,也即前台登录了后台就退出了,后台登录了前台就退出了。出现这种原因的根本原因是我们使用了同一个Cwebuser实例,不能同时设置前后台session,要解决这个问题就要将前后台使用不同的Cwebuser实例登录。下面是我的做法,首先看protected-&config-&main.php里对前台user(Cwebuser)的配置:
'user'=&array(
'class'=&'WebUser',//这个WebUser是继承CwebUser,稍后给出它的代码
'stateKeyPrefix'=&'member',//这个是设置前台session的前缀
'allowAutoLogin'=&true,//这里设置允许cookie保存登录信息,一边下次自动登录
在你用Gii生成一个admin(即后台模块名称)模块时,会在module-&admin下生成一个AdminModule.php文件,该类继承了CWebModule类,下面给出这个文件的代码,关键之处就在该文件,望大家仔细研究:
class AdminModule extends CWebModule
public function init()
// this method is called when the module is being created
// you may place code here to customize the module or the application
parent::init();//这步是调用main.php里的配置文件
// import the module-level models and componen
$this-&setImport(array(
'admin.models.*',
'ponents.*',
//这里重写父类里的组件
//如有需要还可以参考API添加相应组件
Yii::app()-&setComponents(array(
'errorHandler'=&array(
'class'=&'CErrorHandler',
'errorAction'=&'admin/default/error',
'admin'=&array(
'class'=&'AdminWebUser',//后台登录类实例
'stateKeyPrefix'=&'admin',//后台session前缀
'loginUrl'=&Yii::app()-&createUrl('admin/default/login'),
), false);
//下面这两行我一直没搞定啥意思,貌似CWebModule里也没generatorPaths属性和findGenerators()方法
//$this-&generatorPaths[]='admin.generators';
//$this-&controllerMap=$this-&findGenerators();
public function beforeControllerAction($controller, $action)
if(parent::beforeControllerAction($controller, $action))
$route=$controller-&id.'/'.$action-&
if(!$this-&allowIp(Yii::app()-&request-&userHostAddress) && $route!=='default/error')
throw new CHttpException(403,"You are not allowed to access this page.");
$publicPages=array(
'default/login',
'default/error',
if(Yii::app()-&admin-&isGuest && !in_array($route,$publicPages))
Yii::app()-&admin-&loginRequired();
protected function allowIp($ip)
if(empty($this-&ipFilters))
foreach($this-&ipFilters as $filter)
if($filter==='*' || $filter===$ip || (($pos=strpos($filter,'*'))!==false && !strncmp($ip,$filter,$pos)))
AdminModule 的init()方法就是给后台配置另外的登录实例,让前后台使用不同的CWebUser,并设置后台session前缀,以便与前台session区别开来(他们同事存在$_SESSION这个数组里,你可以打印出来看看)。
这样就已经做到了前后台登录分离开了,但是此时你退出的话你就会发现前后台一起退出了。于是我找到了logout()这个方法,发现他有一个参数$destroySession=true,原来如此,如果你只是logout()的话那就会将session全部注销,加一个false参数的话就只会注销当前登录实例的session了,这也就是为什么要设置前后台session前缀的原因了,下面我们看看设置了false参数的logout方法是如何注销session的:
* Clears all user identity information from persistent storage.
* This will remove the data stored via {@link setState}.
public function clearStates()
$keys=array_keys($_SESSION);
$prefix=$this-&getStateKeyPrefix();
$n=strlen($prefix);
foreach($keys as $key)
if(!strncmp($key,$prefix,$n))
unset($_SESSION[$key]);
看到没,就是利用匹配前缀的去注销的。
到此,我们就可以做到前后台登录分离,退出分离了。这样才更像一个应用,是吧?嘿嘿…
差点忘了说明一下:
Yii::app()-&user //前台访问用户信息方法
Yii::app()-&admin //后台访问用户信息方法
不懂的仔细看一下刚才前后台CWebUser的配置。
附件1:WebUser.php代码:
class WebUser extends CWebUser
public function __get($name)
if ($this-&hasState('__userInfo')) {
$user=$this-&getState('__userInfo',array());
if (isset($user[$name])) {
return $user[$name];
return parent::__get($name);
public function login($identity, $duration) {
$this-&setState('__userInfo', $identity-&getUser());
parent::login($identity, $duration);
附件2:AdminWebUser.php代码
class AdminWebUser extends CWebUser
public function __get($name)
if ($this-&hasState('__adminInfo')) {
$user=$this-&getState('__adminInfo',array());
if (isset($user[$name])) {
return $user[$name];
return parent::__get($name);
public function login($identity, $duration) {
$this-&setState('__adminInfo', $identity-&getUser());
parent::login($identity, $duration);
附件3:前台UserIdentity.php代码
* UserIdentity represents the data needed to identity a user.
* It contains the authentication method that checks if the provided
* data can identity the user.
class UserIdentity extends CUserIdentity
* Authenticates a user.
* The example implementation makes sure if the username and password
* are both 'demo'.
* In practical applications, this should be changed to authenticate
* against some persistent user identity storage (e.g. database).
* @return boolean whether authentication succeeds.
public function authenticate()
$this-&errorCode=self::ERROR_PASSWORD_INVALID;
$user=User::model()-&find('username=:username',array(':username'=&$this-&username));
if ($user)
$encrypted_passwd=trim($user-&password);
$inputpassword = trim(md5($this-&password));
if($inputpassword===$encrypted_passwd)
$this-&errorCode=self::ERROR_NONE;
$this-&setUser($user);
$this-&_id=$user-&
$this-&username=$user-&
//if(isset(Yii::app()-&user-&thisisadmin))
// unset (Yii::app()-&user-&thisisadmin);
$this-&errorCode=self::ERROR_PASSWORD_INVALID;
$this-&errorCode=self::ERROR_USERNAME_INVALID;
unset($user);
return !$this-&errorC
public function getUser()
return $this-&
public function getId()
return $this-&_
public function getUserName()
return $this-&
public function setUser(CActiveRecord $user)
$this-&user=$user-&
附件4:后台UserIdentity.php代码
* UserIdentity represents the data needed to identity a user.
* It contains the authentication method that checks if the provided
* data can identity the user.
class UserIdentity extends CUserIdentity
* Authenticates a user.
* The example implementation makes sure if the username and password
* are both 'demo'.
* In practical applications, this should be changed to authenticate
* against some persistent user identity storage (e.g. database).
* @return boolean whether authentication succeeds.
public function authenticate()
$this-&errorCode=self::ERROR_PASSWORD_INVALID;
$user=Staff::model()-&find('username=:username',array(':username'=&$this-&username));
if ($user)
$encrypted_passwd=trim($user-&password);
$inputpassword = trim(md5($this-&password));
if($inputpassword===$encrypted_passwd)
$this-&errorCode=self::ERROR_NONE;
$this-&setUser($user);
$this-&_id=$user-&
$this-&username=$user-&
// Yii::app()-&user-&setState("thisisadmin", "true");
$this-&errorCode=self::ERROR_PASSWORD_INVALID;
$this-&errorCode=self::ERROR_USERNAME_INVALID;
unset($user);
return !$this-&errorC
public function getUser()
return $this-&
public function getId()
return $this-&_
public function getUserName()
return $this-&
public function setUser(CActiveRecord $user)
$this-&admin=$user-&
希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。

我要回帖

更多关于 yii2 oauth 2认证 的文章

 

随机推荐