简单的 Acl 控制的应用 - 第 2 部分
创建 ACO 的自动化工具
正如前面提到的,没有预建的方法把所有的控制器和动作都输入到 Acl 中。然而,我们都痛恨重复的工作,比如键入一个大型应用程序中的上百个动作。
为此,在 Github 中有一个很方便的插件,叫做AclExtras,可以在Github 下载页面下载。我们会简要介绍如何使用它来生成所有的 ACO。
首先,获取一份该插件的拷贝并解压,或者用 git 克隆,放入目录app/Plugin/AclExtras。然后在 app/Config/boostrap.php 文件中启用该插件,如下所示:
- //app/Config/boostrap.php
- // ...
- CakePlugin::load('AclExtras');
最后,在 CakePHP 终端中执行如下命令:
- ./Console/cake AclExtras.AclExtras aco_sync
这样可以获得所有可用命令的完整说明:
- ./Console/cake AclExtras.AclExtras -h
- ./Console/cake AclExtras.AclExtras aco_sync -h
一旦填充完 acos 表之后,继续创建应用的权限。
设置权限
创建权限很像创建 ACO,没有什么神奇的办法,我也没什么好办法。要允许 ARO 访问 ACO,从外壳(shell)接口使用 AclShell。欲知如何使用,可以运行下面的命令来查看 AclShell的帮助:
- ./Console/cake acl --help
注意 : 需要被引号包起来 ('')
为了用 AclComponent
给予(权限),要在自定义的方法中使用如下的代码:
- $this->Acl->allow($aroAlias, $acoAlias);
现在要添加一些允许/拒绝的语句。在 UsersController
中添加下面的代码到一个临时的函数中,然后从浏览器中访问该网址(例如 http://localhost/cake/app/users/initdb)来运行。如果运行 SELECT * FROM aros_acos
应当看到很多 1 和 -1。一旦确认权限设置好了,就可以删除这个函数:
- public function beforeFilter() {
- parent::beforeFilter();
- $this->Auth->allow('initDB'); // 用完之后就可以删除这一行
- }
- public function initDB() {
- $group = $this->User->Group;
- // 允许 admins 访问一切
- $group->id = 1;
- $this->Acl->allow($group, 'controllers');
- // 允许 managers 访问 posts 和 widgets
- $group->id = 2;
- $this->Acl->deny($group, 'controllers');
- $this->Acl->allow($group, 'controllers/Posts');
- $this->Acl->allow($group, 'controllers/Widgets');
- // 只允许 users 添加和编辑 posts 和 widgets
- $group->id = 3;
- $this->Acl->deny($group, 'controllers');
- $this->Acl->allow($group, 'controllers/Posts/add');
- $this->Acl->allow($group, 'controllers/Posts/edit');
- $this->Acl->allow($group, 'controllers/Widgets/add');
- $this->Acl->allow($group, 'controllers/Widgets/edit');
- // 允许基本用户登出
- $this->Acl->allow($group, 'controllers/users/logout');
- // 加上 exit,避免糟糕的 "missing views" 错误消息
- echo "all done";
- exit;
- }
现在我们建立了一些基本的访问规则。我们允许 administrators 访问所有的资源。Managers 可以访问 posts 和 widgets 中的任何动作。而 users 只能访问 posts 和widgets 的 add 和 edit 动作。
我们需要获得 Group
模型的引用,并且修改它的 id,才能指定需要的 ARO,这是由于AclBehavior
行为的工作方式。AclBehavior
行为并不设置 aros
表中的alias 字段,所以我们必须使用对象引用或者数组,来指定我们需要的 ARO。
你可能已经注意到我故意在 Acl 的权限中省略了 index 和 view 动作。我们要让PostsController
和 WidgetsController
控制器的 view 和 index 动作是公开动作,这允许未经身份验证的用户来查看这些页面,那么这些页面就是公开页面了。然而,你也可以随时从 AuthComponent::allowedActions
方法中删除这些动作,index 和view 动作的权限就会恢复到在 Acl 中的设置。
现在我们要拿掉 users 和 groups 控制器中 Auth->allowedActions
的引用。然后在posts 和 widgets 控制器中添加如下代码:
- public function beforeFilter() {
- parent::beforeFilter();
- $this->Auth->allow('index', 'view');
- }
这些去掉了我们前面的在 users 和 groups 控制器中加入的 '关闭开关',并允许对 posts和 widgets 控制器的 index 和 view 动作的公开访问。在AppController::beforeFilter()
中添加:
- $this->Auth->allow('display');
这让 'display' 动作公开。让我们的 PagesController::display() 公开,这是重要的,因为通常默认路由会将这一行动视为访问应用程序的主页。
登录
我们的应用现在有了访问控制,并且任何企图查看非公开页面的尝试都会重定向到登录页面。不过,我们需要创建登录视图,这样用户才能够登录。如果你还没有这么做,请在app/View/Users/login.ctp
中添加如下代码:
- <h2>Login</h2>
- <?php
- echo $this->Form->create('User', array(
- 'url' => array(
- 'controller' => 'users',
- 'action' => 'login'
- )
- ));
- echo $this->Form->input('User.username');
- echo $this->Form->input('User.password');
- echo $this->Form->end('Login');
如果一个用户已经登录了,添加这个方法到 UsersController 来重定向:
- public function login() {
- if ($this->Session->read('Auth.User')) {
- $this->Session->setFlash('You are logged in!');
- return $this->redirect('/');
- }
- }
你应该已经能够登录了,一切都应该自动工作了。如果你添加了echo $this->Session->flash('auth')
,当被拒绝访问的时候就会看到 Auth 组件的消息。
登出
现在轮到登出了。之前我们让这个方法为空,现在是时候实现它了。在UsersController::logout()
中添加如下代码:
- $this->Session->setFlash('Good-Bye');
- $this->redirect($this->Auth->logout());
这设置了会话闪现提示消息,并且使用 Auth 组件的 logout 方法登出用户。Auth 组件的logout 方法基本上是删除 Auth 的会话键(Session Key),并且返回可用于重定向的网址。如果有其它的会话数据也需要删除,也要在这里添加代码。
全部完成
现在你应该已经有一个使用 Auth 和 Acl 组件控制的应用程序了。用户的权限在组(group)一级设置,但是也可以同时在用户(user)一级进行设置。你也可以按全局、按控制器和按动作来设置权限。此外,你有一组可重用的代码块,可以随着你的应用程序的成长,容易地扩展 ACO 表。