Yii 学习
RBAC
进行赋权
我们建立了RBAC权限管理,就需要进行对权限的WEB管理。这些就需要你自己写代码了。
根据不同种类的项目调用下列方法之一定义授权项目:
·CAuthManager::createRole
·CAuthManager::createTask
·CAuthManager::createOperation
一旦我们拥有一套授权项目,我们可以调用以下方法建立授权项目关系:
·CAuthManager::addItemChild
·CAuthManager::removeItemChild
·CAuthItem::addChild
·CAuthItem::removeChild
最后,我们调用下列方法来分配角色项目给各个用户:
·CAuthManager::assign
·CAuthManager::revoke
下面我们将展示一个例子是关于用所提供的API建立一个授权等级:
$auth=Yii::app()->authManager;
$auth->createOperation(‘createPost’,’create a post’);
$auth->createOperation(‘readPost’,’read a post’);
$auth->createOperation(‘updatePost’,’update a post’);
$auth->createOperation(‘deletePost’,’delete a post’);
$bizRule=’return Yii::app()->user->id==$params[“post”]->authID;’;
$task=$auth->createTask(‘updateOwnPost’,’update a post by author himself’,$bizRule);
$task->addChild(‘updatePost’);
$role=$auth->createRole(‘reader’);
$role->addChild(‘readPost’);
$role=$auth->createRole(‘author’);
$role->addChild(‘reader’);
$role->addChild(‘createPost’);
$role->addChild(‘updateOwnPost’);
$role=$auth->createRole(‘editor’);
$role->addChild(‘reader’);
$role->addChild(‘updatePost’);
$role=$auth->createRole(‘admin’);
$role->addChild(‘editor’);
$role->addChild(‘author’);
$role->addChild(‘deletePost’);
$auth->assign(‘reader’,’readerA’);
$auth->assign(‘author’,’authorB’);
$auth->assign(‘editor’,’editorC’);
$auth->assign(‘admin’,’adminD’);
也就是说,你需要自己写一个管理界面,来列出你的角色、任务、行动,然后可以在这个界面上进行管理。比如增加、删除、修改。
权限检查
假设你在你的管理界面进行了赋权,那么可以在程序里面进行权限检查:
if( Yii::app()->user->checkAccess(‘createPost’) )
{
// 这里可以显示表单等操作
} else {
// 检查没有通过的可以跳转或者显示警告
}
上面的代码就检查了用户是否可以执行“createPost”,这createPost可能是一个任务,也可以是一个行动。
其他的
对于很多说Yii权限体系RBAC不好用的人其实都没有看懂文档。综合我的体验,我感觉Yii框架的RBAC是我用过的框架里面最好用的。而且是需要自己写代码最少的。
Yii的RBAC有更加高级的用法,比如“业务规则”,“默认角色”。你可以去参考官方文档。
我知道,会有部分人仍旧不理解RBAC,或者不会用Yii的RBAC。没有关系,你可以在下方的评论框里提问。
happy Yii !
在 yii 中使用 Filter 实现 RBAC 权限自动判断
关于RBAC的使用,我曾经写过一篇文章Yii中使用RBAC完全指南,里面详细介绍了RBAC的部分概念和在Yii中的使用方法。
在具体的权限判断的时候,使用了user组件的checkAccess方法。但是在使用的时候发现,虽然这个方法是很方便的,但是总不能在每个Action里面都写上权限判断吧,那么每个Action中都会出现以下的代码:
if(Yii::app()->user->checkAccess(‘admin’))
{
//验证通过,进行操作
}else{
//验证不通过,进行登录或者抛出错误页面
重复这样的步骤很是令人崩溃。其实,在日常使用的时候经常是对于Action级别进行权限判断。在Yii中早已准备好了现成的代码:
<?php
class XXXController extends CController
{
public function filters()
{
return array(‘accessControl’);
}
public function accessRules()
{
return array(
array(‘allow’, ‘roles’=>array(‘admin’, ‘editor’)));
}
accessControl是一个过滤器,会在controller执行的时候进行权限判断。权限规则写在accessRules里面。上面的代码就对所有Action只允许有admin和editor角色的用户访问。
进一步书写accessRules,你可以精确控制所有的权限。从IP到用户名再到角色,不同的Action进行不同的权限判断,都可以在规则里面写出来。
关于这个规则的具体写法,官方的指南里面有写,具体位置在:Special Topics => Authentication and Authorization。中文版在:。
下载地址:
1.0.x版本 Documentation: .tar.gz, .zip
1.1.x版本 Documentation: .tar.gz, .zip
现在1.1.x版本已经稳定,建议大家使用1.1版本。
Creating Extensions (创建扩展)
由于扩展意味着是第三方开发者使用,需要一些额外的努力去创建它。以下是一些一般性的指导原则:
*扩展最好是自己自足。也就是说,其外部的依赖应是最少的。如果用户的扩展需要安装额外的软件包,类或资源档案,这将是一个头疼的问题。 *文件属于同一个扩展的,应组织在同一目录下,目录名用扩展名称。 *扩展里面的类应使用一些单词字母前缀,以避免与其他扩展命名冲突。 *扩展应该提供详细的安装和API文档。这将减少其他开发员使用扩展时花费的时间和精力。 *扩展应该用适当的许可。如果您想您的扩展能在开源和闭源项目中使用,你可以考虑使用许可证,如BSD的, 麻省理工学院 等,但不是GPL的,因为它要求其衍生的代码是开源的。
在下面,我们根据 overview中所描述的分类,描述如何创建一个新的扩展。当您要创建一个主要用于在您自己项目的component部件,这些描述也适用。
Application Component (应用部件)
一个application component 应实现接口IApplicationComponent或继承CApplicationComponent。主要需要实现的方法是 IApplicationComponent::init,部件在此执行一些初始化工作。此方法在部件创建和属性值(在application configuration里指定的 )被赋值后调用。
默认情况下,一个应用程序部件创建和初始化,只有当它首次访问期间要求处理。如果一个应用程序部件需要在应用程序实例被创建后创建,它应要求用户在CApplication::preload 的属性中列出他的编号。
Widget (小工具)
widget应继承CWidget或其子类。 A widget should extend from CWidget or its child classes.
最简单的方式建立一个新的小工具是继承一个现成的小工具和重载它的方法或改变其默认的属性值。例如,如果您想为CTabView使用更好的CSS样式,您可以配置其CTabView::cssFile属性,当使用的小工具时。您还可以继承CTabView如下,让您在使用小工具时,不再需要配置属性。
class MyTabView extends CTabView
{
public function init()
{
if($this->cssFile===null)
{
$file=dirname(__FILE__).DIRECTORY_SEPARATOR.’tabview.css’;
$this->cssFile=Yii::app()->getAssetManager()->publish($file);
}
parent::init();
}
}
在上面的,我们重载CWidget::init方法和指定CTabView::cssFile的URL到我们的新的默认CSS样式如果此属性未设置时。我们把新的CSS样式文件和MyTabView类文件放在相同的目录下,以便他们能够封装成扩展。由于CSS样式文件不是通过Web访问,我们需要发布作为一项asset资源。
要从零开始创建一个新的小工具,我们主要是需要实现两个方法:CWidget::init 和CWidget::run。第一种方法是当我们在视图中使用 $this->beginWidget 插入一个小工具时被调用,第二种方法在$this->endWidget被调用时调用。如果我们想在这两个方法调用之间捕捉和处理显示的内容,我们可以开始output buffering在CWidget::init 和在CWidget::run中回收缓冲输出作进一步处理。 If we want to capture and process the content displayed between these two method invocations, we can start output buffering in CWidget::init and retrieve the buffered output in CWidget::run for further processing.
在网页中使用的小工具,小工具往往包括CSS,Javascript或其他资源文件。我们叫这些文件assets,因为他们和小工具类在一起,而且通常Web用户无法访问。为了使这些档案通过Web访问,我们需要用CWebApplication::assetManager发布他们,例如上述代码段所示。此外,如果我们想包括CSS或JavaScript文件在当前的网页,我们需要使用CClientScript注册 :
class MyWidget extends CWidget
{
protected function registerClientScript()
{
// …publish CSS or JavaScript file here…
$cs=Yii::app()->clientScript;
$cs->registerCssFile($cssFile);
$cs->registerScriptFile($jsFile);
}
}
小工具也可能有自己的视图文件。如果是这样,创建一个目录命名views在包括小工具类文件的目录下,并把所有的视图文件放里面。在小工具类中使用$this->render(‘ViewName’) 来render渲染小工具视图,类似于我们在控制器里做。
Action (动作)
action应继承CAction或者其子类。action要实现的主要方法是IAction::run 。
Filter (过滤器)
filter应继承CFilter 或者其子类。filter要实现的主要方法是CFilter::preFilter和CFilter::postFilter。前者是在action之前被执行,而后者是在之后。
class MyFilter extends CFilter
{
protected function preFilter($filterChain)
{
// logic being applied before the action is executed
return true;// false if the action should not be executed
}
protected function postFilter($filterChain)
{
// logic being applied after the action is executed
}
}
参数$filterChain的类型是CFilterChain,其包含当前被filter的action的相关信息。
Controller (控制器)
controller要作为扩展需继承CExtController,而不是 CController。主要的原因是因为CController 认定控制器视图文件位于application.views.ControllerID 下,而CExtController认定视图文件在views目录下,也是包含控制器类目录的一个子目录。因此,很容易重新分配控制器,因为它的视图文件和控制类是在一起的。
Validator (验证)
Validator需继承CValidator和实现CValidator::validate attribute 方法。
class MyValidator extends CValidator
{
protected function validateAttribute($model,$attribute)
{
$value=$model->$attribute;
if($value has error)
$model->addError($attribute,$errorMessage);
}
}
Console Command (控制台命令)
console command 应继承CConsoleCommand和实现CConsoleCommand::run方法。 或者,我们可以重载CConsoleCommand::getHelp来提供一些更好的有关帮助命令。
class MyCommand extends CConsoleCommand
{
public function run($args)
{
// $args gives an array of the command-line arguments for this command
}
public function getHelp()
{
return ‘Usage: how to use this command’;
}
}
Module (模块)
请参阅modules一节中关于就如何创建一个模块。
一般准则制订一个模块,它应该是独立的。模块所使用的资源文件(如CSS , JavaScript ,图片),应该和模块一起分发。还有模块应发布它们,以便可以Web访问它们 。
Generic Component (通用组件)
开发一个通用组件扩展类似写一个类。还有,该组件还应该自足,以便它可以很容易地被其他开发者使用。
YII 常用配置方法(含多环境)
index.php
配置环境常量,不同环境调用不同配置文件和调试级别。
查看源代码
打印帮助
1 | /** | |
2 | * 应用程序环境,可选:development,test,production, | |
3 | */ | |
4 | defined(‘APP_ENV’) or define(‘APP_ENV’,’development’); | |
5 | ||
6 | // change the following paths if necessary | |
7 | if (APP_ENV == ‘production’) { |
8 | $yii=dirname(__FILE__).’/../yii-svn/framework/yiilite.php’; |
9 | defined(‘YII_TRACE_LEVEL’) or define(‘YII_TRACE_LEVEL’,1); | |
10 | } else { | |
11 | $yii=dirname(__FILE__).’/../yii-svn/framework/yii.php’; |
12 | // remove the following lines when in production mode |
13 | defined(‘YII_DEBUG’) or define(‘YII_DEBUG’,true); |
14 | // specify how many levels of call stack should be shown in each log message |
15 | defined(‘YII_TRACE_LEVEL’) or define(‘YII_TRACE_LEVEL’,3); | |
16 | } | |
17 | $config=dirname(__FILE__).’/protected/config/’.APP_ENV.’.php’; | |
18 | ||
19 | require_once($yii); |
20 | Yii::createWebApplication($config)->run(); |
main.php
中文及utf8配置
查看源代码
打印帮助
1 | return array( | |
2 | ‘language’=>’zh_cn’, | |
3 | ‘timeZone’=>’Asia/Shanghai’, |
4 | ‘charset’=>’utf-8’, |
5 | //… | |
6 | ) | |
development.php
开启weblog,profile,数据库性能显示,数据库查询参数记录,GII
查看源代码
打印帮助
1 | <?php | |
2 | ||
3 | return CMap::mergeArray( |
4 | require(dirname(__FILE__).’/main.php’), |
5 | array( |
6 | ‘components’=>array( |
7 | // uncomment the following to use a MySQL database |
8 | ‘db’=>array( |
9 | ‘connectionString’=>’mysql:host=localhost;dbname=dbname’, |
10 | ’emulatePrepare’=>true, |
11 | ‘username’=>’root’, |
12 | ‘password’=>’sa’, |
13 | ‘charset’=>’utf8’, |
14 | ‘tablePrefix’=>”, |
15 | ‘enableProfiling’=>true, |
16 | ‘schemaCachingDuration’=>0, |
17 | ‘enableParamLogging’=>true, |
18 | ), |
19 | ‘log’=>array( |
20 | ‘class’=>’CLogRouter’, |
21 | ‘routes’=>array( |
22 | array( |
23 | ‘class’=>’CFileLogRoute’, |
24 | ‘levels’=>’error, warning’, |
25 | ), |
26 | array( |
27 | ‘class’=>’CProfileLogRoute’, |
28 | ), |
29 | array( |
30 | ‘class’=>’CWebLogRoute’, |
31 | ), |
32 | ), |
33 | ), |
34 | ), |
35 | ‘modules’=>array( |
36 | // uncomment the following to enable the Gii tool |
37 | ‘gii’=>array( |
38 | ‘class’=>’system.gii.GiiModule’, |
39 | ‘password’=>’sa’, |
40 | // If removed, Gii defaults to localhost only. Edit carefully to taste. |
41 | ‘ipFilters’=>array(‘127.0.0.1′,’::1′), |
42 | ), |
43 | ), |
44 | ) |
45 | ); |
production.php
开启数据库结构缓存,开启CEAcceleratorCache,关闭错误显示
查看源代码
打印帮助
1 | <?php | |
2 | return CMap::mergeArray( | |
3 | require(dirname(__FILE__).’/main.php’), | |
4 | array( | |
5 | ‘components’=>array( |
6 | // uncomment the following to use a MySQL database |
7 | ‘db’=>array( |
8 | ‘connectionString’=>’mysql:host=localhost;dbname=dbname’, |
9 | ’emulatePrepare’=>true, |
10 | ‘username’=>’root’, |
11 | ‘password’=>’sa’, |
12 | ‘charset’=>’utf8’, |
13 | ‘tablePrefix’=>”, |
14 | ‘enableProfiling’=>false, |
15 | ‘schemaCachingDuration’=>3600, |
16 | ‘enableParamLogging’=>false, |
17 | ), |
18 | ‘log’=>array( |
19 | ‘class’=>’CLogRouter’, |
20 | ‘routes’=>array( |
21 | array( |
22 | ‘class’=>’CFileLogRoute’, |
23 | ‘levels’=>’error, warning’, |
24 | ) |
25 | ), |
26 | ), |
27 | ‘cache’=>array( |
28 | ‘class’=>’system.caching.CEAcceleratorCache’, |
29 | ), |
30 | ), |
31 | ) | |
32 | ); | |