文档章节

CakePHP的blog教程三

victorruan
 victorruan
发布于 2014/07/16 09:52
字数 2395
阅读 33
收藏 0

简单的身份验证和授权应用

接着我们blog教程的例子,如果我们想要建立一个根据登录的用户身份来决定其安全访问到正确的urls。

同时我们还有其他的需求: 允许我们的blog有多个作者,每一个作者都可以自由创作他们自己的posts,编辑和删除它们,而不允许对别人的posts做任何的改动。

创建所有用户的相关代码

首先,让我们在数据库中新建一个表来保存用户的数据

1 CREATE TABLE users (
2     id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
3     username VARCHAR(50),
4     password VARCHAR(50),
5     role VARCHAR(20),
6     created DATETIME DEFAULT NULL,
7     modified DATETIME DEFAULT NULL
8 );

 

我们坚持遵循 CakePHP 的命名约定,同时我们也利用了其他约定:比如在表user中使用username和password, CakePHP 将会自动配置好实现用户登录的大部分工作。

下一步是创建User模型,响应寻找,保存和验证任何用户的数据

 1 // app/Model/User.php
 2 class User extends AppModel {
 3     public $validate = array(
 4         'username' => array(
 5             'required' => array(
 6                 'rule' => array('notEmpty'),
 7                 'message' => 'A username is required'
 8             )
 9         ),
10         'password' => array(
11             'required' => array(
12                 'rule' => array('notEmpty'),
13                 'message' => 'A password is required'
14             )
15         ),
16         'role' => array(
17             'valid' => array(
18                 'rule' => array('inList', array('admin', 'author')),
19                 'message' => 'Please enter a valid role',
20                 'allowEmpty' => false
21             )
22         )
23     );
24 }

让我们也建立我们的控制器 UsersController, 下面的内容是使用 CakePHP 捆绑的代码生成工具生成的基本的UsersController类

 1 // app/Controller/UsersController.php
 2 class UsersController extends AppController {
 3 
 4     public function beforeFilter() {
 5         parent::beforeFilter();
 6         $this->Auth->allow('add');
 7     }
 8 
 9     public function index() {
10         $this->User->recursive = 0;
11         $this->set('users', $this->paginate());
12     }
13 
14     public function view($id = null) {
15         $this->User->id = $id;
16         if (!$this->User->exists()) {
17             throw new NotFoundException(__('Invalid user'));
18         }
19         $this->set('user', $this->User->read(null, $id));
20     }
21 
22     public function add() {
23         if ($this->request->is('post')) {
24             $this->User->create();
25             if ($this->User->save($this->request->data)) {
26                 $this->Session->setFlash(__('The user has been saved'));
27                 $this->redirect(array('action' => 'index'));
28             } else {
29                 $this->Session->setFlash(__('The user could not be saved. Please, try again.'));
30             }
31         }
32     }
33 
34     public function edit($id = null) {
35         $this->User->id = $id;
36         if (!$this->User->exists()) {
37             throw new NotFoundException(__('Invalid user'));
38         }
39         if ($this->request->is('post') || $this->request->is('put')) {
40             if ($this->User->save($this->request->data)) {
41                 $this->Session->setFlash(__('The user has been saved'));
42                 $this->redirect(array('action' => 'index'));
43             } else {
44                 $this->Session->setFlash(__('The user could not be saved. Please, try again.'));
45             }
46         } else {
47             $this->request->data = $this->User->read(null, $id);
48             unset($this->request->data['User']['password']);
49         }
50     }
51 
52     public function delete($id = null) {
53         if (!$this->request->is('post')) {
54             throw new MethodNotAllowedException();
55         }
56         $this->User->id = $id;
57         if (!$this->User->exists()) {
58             throw new NotFoundException(__('Invalid user'));
59         }
60         if ($this->User->delete()) {
61             $this->Session->setFlash(__('User deleted'));
62             $this->redirect(array('action' => 'index'));
63         }
64         $this->Session->setFlash(__('User was not deleted'));
65         $this->redirect(array('action' => 'index'));
66     }
67 }

 

同样的,我们使用代码生成工具,创建blog的posts的视图。为了教学目的,这里仅展示视图add.ctp:

 1 <!-- app/View/Users/add.ctp -->
 2 <div class="users form">
 3 <?php echo $this->Form->create('User'); ?>
 4     <fieldset>
 5         <legend><?php echo __('Add User'); ?></legend>
 6 <?php echo $this->Form->input('username');
 7         echo $this->Form->input('password');
 8         echo $this->Form->input('role', array(
 9             'options' => array('admin' => 'Admin', 'author' => 'Author')
10         ));
11     ?>
12     </fieldset>
13 <?php echo $this->Form->end(__('Submit')); ?>
14 </div>

 

身份验证 (登录 和 登出)

我们现在已经准备好添加我们的认证层了。

在 CakePHP 中,这个功能是由 AuthComponent 完成的,这个组件会为特定动作要求用户登录,处理用户登录和登出,并且检查用户是否有权限进行相应动作(即访问特定页面)。

添加这个组件到应用中,打开 app/Controller/AppController.php 文件,添加如下代码

 1 // app/Controller/AppController.php
 2 class AppController extends Controller {
 3     //...
 4 
 5     public $components = array(
 6         'Session',
 7         'Auth' => array(
 8             'loginRedirect' => array('controller' => 'posts', 'action' => 'index'),
 9             'logoutRedirect' => array('controller' => 'pages', 'action' => 'display', 'home')
10         )
11     );
12 
13     public function beforeFilter() {
14         $this->Auth->allow('index', 'view');
15     }
16     //...
17 }

 

这里没有什么需要配置的,因为我们前面遵循了user表的命名约定,我们只设置了登录后和登出后页码转到的urls,在我们的例子中,分别是 /posts/ 和 / 。

我们在 `` beforeFilter`` 中所做的功能是告诉组件 AuthComponent,在控制器中的所有 index 和 view 行动都不需要登录。我们希望我们的访问者能够读取和列出posts,而不需要注册网站。

现在,我们需要实现新用户的注册。保存它们的用户名和密码,而更重要的是,在我们的数据库中保存用户的hash过的密码而不是用普通文本形式保存,让我们告诉 AuthComponent 组件让未验证的用户访问用户添加函数并实现登录和登出动作

// app/Controller/UsersController.php

public function beforeFilter() {
    parent::beforeFilter();
    $this->Auth->allow('add'); // Letting users register themselves
}

public function login() {
    if ($this->request->is('post')) {
        if ($this->Auth->login()) {
            $this->redirect($this->Auth->redirect());
        } else {
            $this->Session->setFlash(__('Invalid username or password, try again'));
        }
    }
}

public function logout() {
    $this->redirect($this->Auth->logout());
}

散列密码还没有做,打开User模型 app/Model/User.php 添加代码

// app/Model/User.php
App::uses('AuthComponent', 'Controller/Component');
class User extends AppModel {

// ...

public function beforeSave($options = array()) {
    if (isset($this->data[$this->alias]['password'])) {
        $this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
    }
    return true;
}

// ...

现在,每次用户密码保存的时候,都会使用 AuthComponent 组件提供的默认的类进行散列化。为登录创建模板视图 :

<div class="users form">
<?php echo $this->Session->flash('auth'); ?>
<?php echo $this->Form->create('User'); ?>
 <fieldset>
 <legend><?php echo __('Please enter your username and password'); ?></legend>
<?php echo $this->Form->input('username');
        echo $this->Form->input('password');
    ?>
 </fieldset>
<?php echo $this->Form->end(__('Login')); ?>
</div>

现在你可以访问 /users/add 地址来注册一个新的用户了。注册完成后访问 /users/login 地址登录, 试试访问其他地址比如像/posts/add 这些没有明确允许的地址,你会看到应用会自动的转向到登录页面。

就是这!简单到不可思议。让我们返回去稍微解释下。 beforeFilter 函数告诉AuthComponent组件在UsersController中对 add 动作不需要登录,并且在AppController中的 beforeFilter 也已经设置所有的控制器的``index`` and view 动作都是可以不登录的。

login 动作执行AuthComponent中的 $this->Auth->login() 函数且不需要其他的设置的原因是我们遵循了之前提到的在数据库中的user表的命名约定,并且使用表单提交用户的数据到控制器。这个函数返回登录成功还是失败,如果成功,就重定向到我们设置的登录成功的跳转页面。

登出函数只需要访问 /users/logout 并且重定向到先前配置的 logoutUrl。这个url是 AuthComponent::logout() 函数返回登出成功后的跳转的页面。

权限(谁可以访问什么)

前面已经说了,我们要把这个blog应用改为可以多个用户创作的工具,为了做到这个,我们需要修改posts表,添加对User模型的引用

ALTER TABLE posts ADD COLUMN user_id INT(11);

同时,在PostsController中对新增的post做改动,添加当前登录的用户为作者

   // app/Controller/PostsController.php
   public function add() {
       if ($this->request->is('post')) {
           $this->request->data['Post']['user_id'] = $this->Auth->user('id'); //Added this line
           if ($this->Post->save($this->request->data)) {
               $this->Session->setFlash('Your post has been saved.');
               $this->redirect(array('action' => 'index'));
           }
       }
   }

``user()`` 函数提供由组件提供,返回当前登录用户的所有列的数据.我们使用这个方法获得所需的用户信息。

让我们增强应用的安全性,避免用户编辑或删除其他用户的posts,基本的规则是管理用户可以访问任何的url地址,当前的用户(作者角色)只可以访问到允许的地址。打开 AppController 类,在 Auth 的配置中增加更多选项

// app/Controller/AppController.php

public $components = array(
    'Session',
    'Auth' => array(
        'loginRedirect' => array('controller' => 'posts', 'action' => 'index'),
        'logoutRedirect' => array('controller' => 'pages', 'action' => 'display', 'home'),
        'authorize' => array('Controller') // Added this line
    )
);

public function isAuthorized($user) {
    // Admin can access every action
    if (isset($user['role']) && $user['role'] === 'admin') {
        return true;
    }

    // Default deny
    return false;
}

我们只创建了一个非常简单的权限机制。在这个例子中用户登录后角色是``admin`` 的将可以访问任何地址,而其余的(例如角色author ) 同未登录的用户一样不能够做任何事。

这并不是我们所想要的,所以我们需要在我们的 isAuthorized() 方法中支持更多的规则. 与其在 AppController中设置, 不如委托每个控制器提供这些额外的规则。我们要在PostsController中增加规则,允许作者创建posts并且防止其他作者对其post做改动。打开PostsController.php 并添加如下内容

// app/Controller/PostsController.php

public function isAuthorized($user) {
    // All registered users can add posts
    if ($this->action === 'add') {
        return true;
    }

    // The owner of a post can edit and delete it
    if (in_array($this->action, array('edit', 'delete'))) {
        $postId = $this->request->params['pass'][0];
        if ($this->Post->isOwnedBy($postId, $user['id'])) {
            return true;
        }
    }

    return parent::isAuthorized($user);
}

我们现在重写了 AppController 的 isAuthorized() 方法并且在父类中已核准用户后再进行内部检查,如果他不是,只允许他访问add动作, 并有条件访问edit 和 delete动作. 在 Post 模型中调用 isOwnedBy() 来告诉用户是否有权限来编辑post. 尽量把逻辑挪到模型中是个很好的实践。让我们实现它

// app/Model/Post.php

public function isOwnedBy($post, $user) {
    return $this->field('id', array('id' => $post, 'user_id' => $user)) === $post;
}

简单的身份验证和授权教程到这里就结束了。可以参考我们在PostsController中所做的用到UsersController中,你应该也会更具创作性并可根据你自己的规则在 AppController 添加一般规则。

更多信息,参阅完整的Auth指导 Authentication 授权认证 ,这里你可以找到更多组件配置,创建自主的权限类等

本文转载自:http://www.cnblogs.com/victorruan/p/3557286.html

victorruan
粉丝 0
博文 13
码字总数 0
作品 0
徐汇
私信 提问
在 Windows Azure 网站上运行 CakePHP 应用

上周我搞了个简单的 CakePHP 应用并在 Windows Azure 上跑了起来。 CakePHP是一个运用了诸如ActiveRecord、Association Data Mapping、Front Controller和MVC等著名设计模式的快速开发框架。...

红薯
2012/08/02
1K
4
CakePHP 2.x CookBook 中文版 第三章 入门(三)

路由 多数情况下,CakePHP 的默认路由都能够很好地工作。对用户体验和搜索引擎兼容敏感的程序员将注意到 CakePHP 的 URL 映射到动作的方式。所以在这篇教程里我们仅仅快速的更改了一下路由。...

lht007
2013/03/21
46
0
在 Windows Azure 网站上运行 CakePHP 应用

上周我搞了个简单的 CakePHP 应用并在 Windows Azure 上跑了起来。 CakePHP是一个运用了诸如ActiveRecord、Association Data Mapping、Front Controller和MVC等著名设计模式的快速开发框架。...

tsl0922
2012/11/26
149
0
CakePHP 2.0 发布,PHP的Web应用框架

CakePHP开发团队已经发布了CakePHP 2.x系列的一个版本CakePHP 2.0。在该版本中不再支持PHP4,CakePHP团队对其代码库进行了重构,以便严格遵循PHP 5规范(包括5.2及以后版本)。 CakePHP是一个...

鉴客
2011/10/19
2.3K
2
CakePHP 3.4.0 和 3.3.15 发布,PHP 开发框架

CakePHP 核心团队很高兴地宣布 CakePHP 3.4.0 和 3.3.15 发布了,CakePHP 是一个 PHP 的快速开发框架,使用常见的设计模式,如关联数据映射、前端控制器和 MVC。 主要目标是提供一个结构化框...

两味真火
2017/02/13
1K
3

没有更多内容

加载失败,请刷新页面

加载更多

PCB设计-Allegro软件入门系列-铺铜操作(下)

铺铜是PCB很常见的操作,PCB的敷铜一般都是覆地铜,增大地线面积,有利于地线阻抗降低,使电源和信号传输稳定,在高频的信号线附近敷铜,可大大减少电磁辐射干扰,起屏蔽作用。 本讲讲解啊一...

demyar
4分钟前
1
0
如何通过WASI SDK 在Linux上编译ZXing C++

Mozilla在今年三月份的时候公布了WASI。WASI的目标就是让WebAssembly在任何地方都可以运行,而不仅仅像现在这样只能运行在Node.js和Web浏览器中。WASI目前依然处于初级阶段,这篇文章分享下如...

yushulx
6分钟前
1
0
.Net界面开发神器—DevExpress官方汉化包免费下载!还在等什么?

点击获取DevExpress v19.1.7新版试用下载 DevExpress Localization Service允许您创建一组自定义的附属程序集,要将语言包添加到程序集中,请查看本文中为大家列出的对应版本的汉化包,下载并...

FILA6666
6分钟前
2
0
php生成二维码

        header('Content-Type: image/png');        //清除缓冲区,防止之前面不知道的情况下被加头部信息导致不显示图片内容        ob_clean();        $...

横着走的螃蟹
12分钟前
2
0
伪类和伪元素

伪类和伪元素 伪类和伪元素,对于绝大多数同学来说,都是耳熟能详的名字,但确实又有很多人搞不清楚它们之间的区别,以致于混淆概念。而当概念都混淆的时候,也往往意味着你不会经常使用它,...

不负好时光
14分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部