Trong Bài 12 – Ứng dụng đăng nhập trong Cakephp, các bạn đã làm quen với việc sử dụng và quản lý Session. Còn trong bài này , chúng ta sẽ sử dụng Component Authentication của Cakephp để xác thực người dùng . Component Authentication giúp ta xử lý linh hoạt hơn trong việc xác thực người dùng truy cập.

Mục đích:

Tạo một ứng dụng web, bắt được người dùng phải sử dụng username và pass để đăng nhập, hệ thống sẽ kiểm tra quyền, nếu quyền là 1 sẽ được phép thêm, sửa, xóa thông tin user của mình và thông tin user khác, còn nếu quyền là 2 thì chỉ cho phép xem thông tin user mình và thông tin user khác

Các bước chuẩn bị

– Sử dụng project cakephp

– Đối với bảng users trong db cakephp ta thêm vào một trường level để xác định quyền, các bạn chạy câu lệnh sau trong SQL của phpmyadmin để thêm vào:

ALTER TABLE `users` ADD `level` INT( 2 ) NOT NULL DEFAULT '1';

– Cấu hình router để viết cho trang admin, mở file core.php trong app\Config\ tìm đến đoạn


//Configure::write('Routing.prefixes', array('admin'));

bỏ 2 dấu // đi để mở cấu hình cho admin save file này lại

Từ nay khi viết một function trong controller để nó sử dụng trong admin thì sẽ có dạng function admin_list(){ }

Ví dụ ta có controllers users và có 2 hàm trong controllers này tương ứng 2 view, 1 là list và 1 là edit

Với 2 dường dẫn:

– http://localhost:8080/cakephp/admin/users/edit/1

– http://localhost:8080/cakephp/users/list

Nội dung controllers sẽ là:

class UsersController extends AppController{
   public $name = "Users";
   //Ứng với đường dẫn http://localhost:8080/cakephp/admin/users/edit/1
   function admin_edit(){

   }
   //Ứng với đường dẫn http://localhost:8080/cakephp/users/list
   function list(){

   }
}

điều trên cũng đồng nghĩa với 2 file trong view Users là admin_edit.ctp và list.ctp.

Viết ứng dụng:

File AppController.php

<?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $components = array(
   'Auth'=>array(
     'userModel' => 'User',//sử dụng model User
     'fields' => array('username' => 'username', 'password' => 'password'),//sử dụng 2 field "username","password" để so sánh xem có hợp lệ không
     'loginAction' => array('admin'=>false, 'controller'=>'users', 'action'=>'login'),//Khi chưa đăng nhập sẽ tự chuyển tới
     'loginRedirect' => array('admin'=>true, 'controller'=>'users', 'action'=>'index'),//Khi đăng nhập thành công
     'authError' => 'Không thể truy cập',//báo lỗi
     'authorize' => array('Controller'),
   )
   //ngay chổ admin có 2 giá trị true và false,
 );
 function beforeFilter(){
   Security::setHash("md5");//mã hóa password là md5
   $this->set('current_user', $this->Auth->user());//sau khi đăng nhập thành công biến current_user là thông tin user đăng nhập
 }
 function isAuthorized(){
   return true;
 }
}

Trong nội dung này có sử dụng components Auth để tiến hành đăng nhập với ý nghĩa có ghi rõ trong nội dung trên.

Tiếp theo là file model User.php

<?php
class User extends AppModel{
    var $name = "User";
    function validateUser(){
       $this->validate = array(
         "username"=>array(
           "rule1" =>array(
              "rule" => "notBlank",
              "message" => "Username không được rỗng",
           ),
           "rule2" => array(
              "rule" => "/^[a-z0-9_.]{4,}$/i",
              "message" => "Username là kí tự hoặc số",
           ),
           "rule3" =>array(
              "rule" => "checkUsername", // call function check Username
              "message" => "Username đã có người đăng ký",
           ),
         ),
         "pass"=>array(
           "rule" => "notBlank",
           "message" => "Password không được rỗng",
           "on" => "create"
         ),
         "re_pass"=>array(
           "rule1"=>array(
              "rule" => "notBlank",
              "message" => "Password comfirm không được rỗng",
              "on" => "create"
           ),
           "match" => array(
              "rule" => "ComparePass", // call function compare password
              "message" => "Password comfirm không trùng khớp",
           ),
        ),
        "level"=>array(
           "rule" => "notBlank",
           "message" => "Please select level",
        ),
        "email"=>array(
           "rule" => "email",
           "message" => "Email is not avalible",
        ),
        'name' => array(
           'not empty' => array(
              'rule' => 'notBlank',
              'message' => 'Name không được rỗng'
           )
        )
    );
 if($this->validates($this->validate))
    return TRUE;
 else
    return FALSE;
 }
 function ComparePass(){
    if($this->data['User']['pass']!=$this->data['User']['re_pass']){
       return FALSE;
    }else{
       return TRUE;
    }
 }
 function checkUsername(){
    if(isset($this->data['User']['id'])){
      $where = array(
               "id !=" => $this->data['User']['id'],
               "username" => $this->data['User']['username'],
      );
    }else{
      $where = array(
               "username" => $this->data['User']['username'],
      );
    }
  $this->find("first", array(
    'conditions' => $where
  ));
  $count = $this->getNumRows();
  if($count!=0){
     return false;
  }else{
     return true;
  }
 }
 function beforeSave($options = array()){
    if (!empty($this->data['User']['pass'])) {
      $hash = Security::hash($this->data['User']['pass'], 'md5');
      $this->data['User']['password'] = $hash;
    }
    return true;
 }
}

Cách viết cho model chúng ta đã học qua các bạn xem lại, có vấn đề gì thì comment bên dưới, trong đây cần chú ý là hàm

function beforeSave($options = array()){
 if (!empty($this->data['User']['pass'])) {
 $hash = Security::hash($this->data['User']['pass'], 'md5');
 $this->data['User']['password'] = $hash;
 }
 return true;
 }

có nghĩa là trước khi insert vào CSDL thì sẽ mã hóa password dưới thuật toán md5

Tiếp theo là file UsersController.php

<?php
class UsersController extends AppController{
 var $name = "Users";
 var $helpers = array("Html","Session");
 var $components = array("Session");

 function beforeFilter(){
   parent::beforeFilter();
 }
 function index(){
   $data = $this->User->find("all");
   $this->set("data",$data);
 }
 function admin_index(){
   $data = $this->User->find("all");
   $this->set("data",$data);
 }
 function admin_edit($id){
   if (!$id && empty($this->data)) {
    $this->Session->setFlash('User này không phù hợp');
    $this->redirect("/admin/users");//chuyển đến /admin/users/index
   }

   if(empty($this->data)) {
    $this->data = $this->User->read(null, $id);//Lấy thông tin user
   }else{
    $this->User->set($this->data);
    if($this->User->validateUser()){
     $this->User->save($this->data);
     $this->Session->setFlash("Cập nhật user thành công");
     $this->redirect("/admin/users"); //chuyển đến /admin/users/index
    }
   }
 }
 function admin_add() {
   if(!empty($this->data)){
    $this->User->set($this->data);
    if($this->User->validateUser()){
     $this->User->save($this->data);
     $this->Session->setFlash("Thêm user thành công !");
     $this->redirect("/admin/users");
    }
   }else{
    $this->render();
   }
 }
 function admin_delete($user_id){
   if(isset($user_id) && is_numeric($user_id)){
    $data = $this->User->read(null,$user_id);
    if(!empty($data)){
     $this->User->delete($user_id);
     $this->Session->setFlash("Username đã được xóa với với id=".$user_id);
    }else{
     $this->Session->setFlash("Username không tồn tại với id=".$user_id);
    }
   }else{
    $this->Session->setFlash("Username không tồn tại");
   }
   $this->redirect("/admin/users");
 }
 function login(){
   if($this->request->is('post')){
    if($this->Auth->login()){
     if ($this->Auth->user('level') == 1){
      $this->redirect("/admin/users/index");
     }else{
      $this->redirect("/users/index");
     }
    }else{
     $this->Session->setFlash('Username hoặc password sai','default',array('class'=>"alert alert-success"));
    }
   }
 }
 function logout(){
   $this->redirect($this->Auth->logout());
 }
}

Trong đó có hàm


function beforeFilter(){
  parent::beforeFilter();
 }

nó sẽ gọi hàm beforeFilter() của AppControllers sẽ kiểm tra đăng nhập khi truy cập vào controllers users

Trong file còn có $this->data là dữ liệu được lấy từ form dạng mảng.

Cuối cùng là tạo các file trong view Users:

login.ctp(trang đăng nhập)

<html>
<body>
<div class="form-box" id="login-box">
 <div class="header">Sign In</div>
 <?=$this->Form->create();?>
 <?=$this->Form->input('username');?>
 <?=$this->Form->input('password');?>
 <button type="submit">Sign me in</button>
 <?=$this->Form->end();?>
</div>
</body>
</html>

index.ctp(danh sách khi đăng nhập là user)

<html>
<body>
<ul>
 <li>Login as User : <?php echo $current_user['username'];?></li>
 <li><a href='<?php echo $this->webroot."users/logout";?>'>Logout</a></li>
</ul>
<?php
if($data==NULL){
 echo "<h2>Dada Empty</h2>";
}
else{
 echo "<table>
 <tr>
 <td>User ID</td>
 <td>Name</td>
 <td>Username</td>
 <td>Email<td>
 </tr>";
 foreach($data as $item){
 echo "<tr>";
 echo "<td>".$item['User']['id']."</td>";
 echo "<td>".$item['User']['name']."</td>";
 echo "<td>".$item['User']['username']."</td>";
 echo "<td>".$item['User']['email']."</td>";
 echo "</tr>";
 }
}
?>
</body>
</html>

admin_index.ctp(danh sách khi đăng nhập admin)

<html>
<body>
<ul>
 <li>Login as : <?php echo $current_user['username'];?></li>
 <li><a href='<?php echo $this->webroot."admin/users";?>'>View Users</a></li>
 <li><a href='<?php echo $this->webroot."admin/users/add";?>'>Add new User</a></li>
 <li><a href='<?php echo $this->webroot."users/logout";?>'>Logout</a></li>
</ul>
<?php
if($data==NULL){
 echo "<h2>Dada Empty</h2>";
}
else{
 echo "<table>
 <tr>
 <td>User ID</td>
 <td>Name</td>
 <td>Username</td>
 <td>Email</td>
 <td>Level</td>
 <td>Options</td>
 </tr>";
 foreach($data as $item){
 echo "<tr>";
 echo "<td>".$item['User']['id']."</td>";
 echo "<td>".$item['User']['name']."</td>";
 echo "<td>".$item['User']['username']."</td>";
 echo "<td>".$item['User']['email']."</td>";
 if($item['User']['level']==1){
 $level = "Admin";
 }else{
 $level = "User";
 }
 echo "<td>".$level."</td>";
 echo "<td><a href='".$this->webroot."admin/users/edit/".$item['User']['id']."' >Edit</a><br>
 <a href='".$this->webroot."admin/users/delete/".$item['User']['id']."' >Del</a></td>";
 echo "</tr>";
 }
}
?>
</body>
</html>

admin_add.ctp(thêm user)

<ul>
 <li>Login as : <?php echo $current_user['username'];?></li>
 <li><a href='<?php echo $this->webroot."admin/users";?>'>View Users</a></li>
 <li><a href='<?php echo $this->webroot."admin/users/add";?>'>Add new User</a></li>
 <li><a href='<?php echo $this->webroot."users/logout";?>'>Logout</a></li>
</ul>
<?php
 echo $this->Form->create('User');
 echo "<fieldset>";
 echo "<legend>Add new User</legend>";
 echo $this->Form->input('name');
 echo $this->Form->input('username');
 echo $this->Form->input('pass',array("type"=>"password"));
 echo $this->Form->input('re_pass',array("type"=>"password"));
 echo $this->Form->input('email');
 $options = array(""=>"Level","1"=>"Admin","2"=>"User");
 echo $this->Form->input("level",array("type"=>"select","options"=>$options));
 echo $this->Form->end('Add new');
 echo "</fieldset>";
?>

admin_edit.ctp(cập nhật user)

<ul>
 <li>Login as : <?php echo $current_user['username'];?></li>
 <li><a href='<?php echo $this->webroot."admin/users";?>'>View Users</a></li>
 <li><a href='<?php echo $this->webroot."admin/users/add";?>'>Add new User</a></li>
 <li><a href='<?php echo $this->webroot."users/logout";?>'>Logout</a></li>
</ul>
<?php
 echo $this->Form->create('User');
 echo "<fieldset>";
 echo "<legend>Edit User</legend>";
 echo $this->Form->input('name');
 echo $this->Form->input('username');
 echo $this->Form->input('pass',array("type"=>"password"));
 echo $this->Form->input('re_pass',array("type"=>"password"));
 echo $this->Form->input('email');
 $options = array(""=>"Level","1"=>"Admin","2"=>"User");
 echo $this->Form->input("level",array("type"=>"select","options"=>$options));
 echo $this->Form->hidden("id");
 echo $this->Form->end('Update User');
 echo "</fieldset>";
?>

Trong các file view trên có cú pháp $this->Form là cách viết ngắn ngọn html form trong CakePHP, tạo form bằng create() và kết thúc form bằng end(), input() sẽ tạo ra các input dạng text, password, email… theo type trong database(phần này sẽ có một bài riêng).

Chạy test:

Chúng ta chạy với url: http://localhost:8080/cakephp/users/login để đăng nhập bằng user trong database.

2015-11-09_162817

Tiến hành đăng nhập với username: nongdanit1,  pass: 123456, sẽ đăng nhập vào được với quyền admin, và chỉnh sửa được các user trong danh sách, tiến hành cập nhật một user khác thành user bình thường, sau đó logout user hiện tại và đăng nhập lại bằng user vừa sửa để test.

Kết luận

  1. Nếu có thắc mắc gì các bạn để lại comment bên dưới mình sẽ trả lời sớm nhất có thể.
  2. Cảm ơn các bạn đã đọc.

Nongdanit.info
[Cakephp] Bài 14 – Component Authentication – xác thực người dùng