Khanh Hoang - Kenn
Kenn is a user experience designer and front end developer who enjoys creating beautiful and usable web and mobile experiences.
1. Nội dung :
- Bài viết tập trung vào phần code và giải thích 1 số hàm quan trọng và cơ chế làm việc khi sử dụng Component Authentication.
2. Các vấn đề liên quan cần phải nắm :
- Sử dụng Form Validation
- Rút ngắn mã lệnh khi tạo form , html ... trong view
3. Viế ứng dụng cụ thể :
- Đầu tiên ta xác định mô hình làm việc của ứng dụng này . Xem tại đây
Sau khi xác định mô hình . Trong app/ tạo app_controller.php với nội dung sau :
<?php
App::import(#DD0000">'Html',#DD0000">"html");
App::import(#DD0000">'Form',#DD0000">"form");
App::import(#DD0000">'Session',#DD0000">"session");
class AppController extends Controller {
var $components = array(#DD0000">'Auth');
#FF8000">/**
* Thuc thi truoc khi goi cac controller con
*/
function beforeFilter()
{
Security::setHash(#DD0000">"md5");
$this->Auth->userModel = #DD0000">'User';
$this->Auth->fields = array(#DD0000">'username' => #DD0000">'username', #DD0000">'password' => #DD0000">'password');
$this->Auth->loginAction = array(#DD0000">'admin' => false, #DD0000">'controller' => #DD0000">'users', #DD0000">'action' => #DD0000">'login');
$this->Auth->loginRedirect = array(#DD0000">'admin' =>true,#DD0000">'controller' => #DD0000">'users', #DD0000">'action' => #DD0000">'index');
$this->Auth->loginError = #DD0000">'Username / password combination. Please try again';
$this->Auth->authorize = #DD0000">'controller';
$this->set(#DD0000">"admin",$this->_isAdmin());
$this->set(#DD0000">"logged_in",$this->_isLogin());
$this->set(#DD0000">"users_userid",$this->_usersUserID());
$this->set(#DD0000">"users_username",$this->_usersUsername());
}
#FF8000">/**
* Xac nhan co phai la admin hay khong
* TRUE : phai
* FASLE : khong
*/
function _isAdmin(){
$admin = FALSE;
if($this->Auth->user(#DD0000">"level")==1)
$admin = TRUE;
return $admin;
}
#FF8000">/**
* Kiem tra da login chua
*/
function _isLogin(){
$login = FALSE;
if($this->Auth->user()){
$login = TRUE;
}
return $login;
}
#FF8000">/**
* Xac nhan userID
*/
function _usersUserID(){
$users_userid = NULL;
if($this->Auth->user())
$users_userid = $this->Auth->user(#DD0000">"id");
return $users_userid;
}
#FF8000">/**
* Xac nhan username
*/
function _usersUsername(){
$users_username = NULL;
if($this->Auth->user())
$users_username = $this->Auth->user(#DD0000">"username");
return $users_username;
}
#FF8000">/**
* Xac nhan co phai truy cap vao trang admin hay khong
*/
function isAuthorized() {
if (isset($this->params[#DD0000">'admin'])) {
if ($this->Auth->user(#DD0000">'level') != 1) {
$this->Auth->allow(#DD0000">"index");
$this->redirect(#DD0000">"/users");
}
}
return true;
}
}
?>
Ghi chú :
- Đối với các mã lệnh
App::import(#DD0000">'Html',#DD0000">"html");
App::import(#DD0000">'Form',#DD0000">"form");
App::import(#DD0000">'Session',#DD0000">"session");
Chúng dùng để rút ngắn mã lệnh khi tạo form trong view và một mã html .. khi cần thiết.
- Để sử dụng Component Authentication ta chỉ cần khai báo :
$components = array(#DD0000">'Auth');
- Trong đây hàm được xem là quan trọng nhất :
function beforeFilter()
{
Security::setHash(#DD0000">"md5");
$this->Auth->userModel = #DD0000">'User';
$this->Auth->fields = array(#DD0000">'username' => #DD0000">'username', #DD0000">'password' => #DD0000">'password');
$this->Auth->loginAction = array(#DD0000">'admin' => false, #DD0000">'controller' => #DD0000">'users', #DD0000">'action' => #DD0000">'login');
$this->Auth->loginRedirect = array(#DD0000">'admin' =>true,#DD0000">'controller' => #DD0000">'users', #DD0000">'action' => #DD0000">'index');
$this->Auth->loginError = #DD0000">'Username / password combination. Please try again';
$this->Auth->authorize = #DD0000">'controller';
$this->set(#DD0000">"admin",$this->_isAdmin());
$this->set(#DD0000">"logged_in",$this->_isLogin());
$this->set(#DD0000">"users_userid",$this->_usersUserID());
$this->set(#DD0000">"users_username",$this->_usersUsername());
}
Hàm beforeFilter() này sẽ được gọi trước gọi function của Controller extends AppController. Đương nhiên là khi ta viết các Controller như : Users hay Products .. Phải extends AppController này rồi .
Trong này hàm :
Security::setHash(#DD0000">"md5");
Có nghĩa là sẽ gán thuật toán mã hóa password là md5 , cái này dùng trong kiểm tra đăng nhập mật khẩu và mã hóa password khi thêm thành viên mới .
$this->Auth->userModel = #DD0000">'User';
$this->Auth->fields = array(#DD0000">'username' => #DD0000">'username', #DD0000">'password' => #DD0000">'password');
Sử dụng table Users với các field "username","password" để so sánh xem có hợp lệ không
$this->Auth->loginAction = array(#DD0000">'admin' => false, #DD0000">'controller' => #DD0000">'users', #DD0000">'action' => #DD0000">'login');
Khi không hợp lệ trang sẽ tự chuyễn tới http://localhost/thu_muc_web/users/login
$this->Auth->loginRedirect = array(#DD0000">'admin' =>true,#DD0000">'controller' => #DD0000">'users', #DD0000">'action' => #DD0000">'index');
Khi hợp lệ nó sẽ tự chuyễn đến http://localhost/thu_muc_web/admin/users/index
$this->set(#DD0000">"admin",$this->_isAdmin());
$this->set(#DD0000">"logged_in",$this->_isLogin());
$this->set(#DD0000">"users_userid",$this->_usersUserID());
$this->set(#DD0000">"users_username",$this->_usersUsername());
Gán dữ liệu cần thiết và khi hợp lệ nó sẽ được hiển thị ở trong phần view
function isAuthorized() {
if (isset($this->params[#DD0000">'admin'])) {
if ($this->Auth->user(#DD0000">'level') != 1) {
$this->Auth->allow(#DD0000">"index");
$this->redirect(#DD0000">"/users");
}
}
return true;
}
Hàm này sẽ thực khi khi đăng nhập thành công (username và password hợp lệ). Sau đó nó kiểm tra level , nếu không phải là 1 (admin) thì chuyển sang trang http://localhost/thu_muc_web/users/index và xem được các trang khác như : delete , edit, add
Vậy là chúng ta đã xong phần quan trọng nhất đó là tạo file app_controller.php
Tiếp theo tạo vào app/controllers/ tạo file users_controller.php với nội dung sau :
<?php
class UsersController extends AppController{
var $name = #DD0000">"Users";
var $helpers = array(#DD0000">"Html",#DD0000">"Session");
var $components = array(#DD0000">"Session");
function beforeFilter(){
parent::beforeFilter();
}
#FF8000">/**
* Trang chu user
*/
function index(){
$data = $this->User->find(#DD0000">"all");
$this->set(#DD0000">"data",$data);
}
#FF8000">/**
* Trang chu admin
*/
function admin_index(){
$data = $this->User->find(#DD0000">"all");
$this->set(#DD0000">"data",$data);
}
#FF8000">/**
* Cap nhat user
*/
function admin_edit($id){
if (!$id && empty($this->data)) {
$this->Session->setFlash(#DD0000">'Invalid User');
$this->redirect(#DD0000">"/admin/users");
}
if (empty($this->data)) {
$level = array(#DD0000">"1"=>#DD0000">"administrator",#DD0000">"2"=>#DD0000">"Assistant");
$this->set(#DD0000">"level",$level);
$this->data = $this->User->read(null, $id);
}else{
$this->User->set($this->data);
if($this->User->validateUser()){
$this->User->save($this->data);
$this->Session->setFlash(#DD0000">"You has been updated user with id =".$id);
$this->redirect(#DD0000">"/admin/users");
}
}
}
#FF8000">/**
* Them moi User
*/
function admin_add() {
if(!empty($this->data)){
$this->User->set($this->data);
if($this->User->validateUser()){
$this->User->save($this->data);
$this->Session->setFlash(#DD0000">"You has been add new User !");
$this->redirect(#DD0000">"/admin/users");
}
}else{
$this->render();
}
}
#FF8000">/**
* Xoa user
*/
function admin_delete($user_id){
if(isset($user_id) && is_numeric($user_id)){
$data = $this->User->read(null,$id);
if(!empty($data)){
$this->User->delete($user_id);
$this->Session->setFlash(#DD0000">"Username has been deleted with id=".$user_id);
}else{
$this->Session->setFlash(#DD0000">"Username is not avalible with id=".$user_id);
}
}else{
$this->Session->setFlash(#DD0000">"Username is not avalible with id=".$user_id);
}
$this->redirect(#DD0000">"/admin/users");
}
#FF8000">/**
* Dang nhap
*/
function login(){
if ($this->Auth->user()) {
$this->redirect($this->Auth->redirect());
}
}
#FF8000">/**
* Dang xuat
*/
function logout(){
$this->redirect($this->Auth->logout());
}
}
Trong đây cái cần chú ý nhất là :
function beforeFilter(){
parent::beforeFilter();
}
Nếu không có hàm này thì không kiểm tra trước khi đăng nhập. Hàm beforeFilter() sẽ gọi ngược lên hàm beforeFilter() của class AppController và kiểm tra đăng nhập mỗi khi truy cập vào Controller User này .
Tiếp theo là tạo các file view tương ứng cho Controller User . Vào app/views/ tạo thư mục users. Sau đó lần lượt tạo các file với nội dung sau :
File admin_add.ctp :
<?php echo $this->element(#DD0000">"backend/navigate");?>
<?php echo $session->flash(); ?>
<?php
echo $form->create(#DD0000">'User');
echo #DD0000">"<fieldset>";
echo #DD0000">"<legend>Add new User</legend>";
echo $form->input(#DD0000">'username');
echo $form->input(#DD0000">'pass',array(#DD0000">"type"=>#DD0000">"password"));
echo $form->input(#DD0000">'re_pass',array(#DD0000">"type"=>#DD0000">"password"));
echo $form->input(#DD0000">'email');
$op_gender = array(#DD0000">'1'=>#DD0000">'Male',#DD0000">'2'=>#DD0000">'Female');
$att = array(
#DD0000">"type"=>#DD0000">"radio",
#DD0000">"options"=>$op_gender,
#DD0000">"legend" => false,
);
echo $form->input(#DD0000">"gender",$att);
$options = array(#DD0000">""=>#DD0000">"Select Level",#DD0000">"1"=>#DD0000">"Administrator",#DD0000">"2"=>#DD0000">"Assistant");
echo $form->input(#DD0000">"level",array(#DD0000">"type"=>#DD0000">"select",#DD0000">"options"=>$options));
echo $form->end(#DD0000">'Add new');
echo #DD0000">"</fieldset>";
?>
File admin_edit.ctp
<?php echo $this->element(#DD0000">"backend/navigate");?>
<?php echo $session->flash(); ?>
<?php
echo $form->create(#DD0000">'User');
echo #DD0000">"<fieldset>";
echo #DD0000">"<legend>Edit User</legend>";
echo $form->input(#DD0000">'username');
echo $form->input(#DD0000">'pass',array(#DD0000">"type"=>#DD0000">"password"));
echo $form->input(#DD0000">'re_pass',array(#DD0000">"type"=>#DD0000">"password"));
echo $form->input(#DD0000">'email');
$op_gender = array(#DD0000">'1'=>#DD0000">'Male',#DD0000">'2'=>#DD0000">'Female');
$att = array(
#DD0000">"type"=>#DD0000">"radio",
#DD0000">"options"=>$op_gender,
#DD0000">"legend" => false,
);
echo $form->input(#DD0000">"gender",$att);
$options = array(#DD0000">""=>#DD0000">"Select Level",#DD0000">"1"=>#DD0000">"Administrator",#DD0000">"2"=>#DD0000">"Assistant");
echo $form->input(#DD0000">"level",array(#DD0000">"type"=>#DD0000">"select",#DD0000">"options"=>$options));
echo $form->hidden(#DD0000">"id");
echo $form->end(#DD0000">'Update User');
echo #DD0000">"</fieldset>";
?>
File admin_index.ctp
<html>
<body>
<?php
#FF8000">//Load navigate
echo $this->element(#DD0000">"backend/navigate");
#FF8000">//Hien thi du lieu
if($data==NULL){
echo #DD0000">"<h2>Dada Empty</h2>";
}
else{
echo #DD0000">"<table>
<tr>
<td>User ID</td>
<td>Username</td>
<td>Email<td>
<td>Level<td>
<td><td>
</tr>";
foreach($data as $item){
echo #DD0000">"<tr>";
echo #DD0000">"<td>".$item[#DD0000">'User'][#DD0000">'id'].#DD0000">"</td>";
echo #DD0000">"<td>".$item[#DD0000">'User'][#DD0000">'username'].#DD0000">"</td>";
echo #DD0000">"<td>".$item[#DD0000">'User'][#DD0000">'email'].#DD0000">"</td>";
if($item[#DD0000">'User'][#DD0000">'level']==1){
$level = #DD0000">"Administrator";
}else{
$level = #DD0000">"Assistant";
}
echo #DD0000">"<td>".$level.#DD0000">"</td>";
echo #DD0000">"<td><a href='".$this->webroot.#DD0000">"admin/users/edit/".$item[#DD0000">'User'][#DD0000">'id'].#DD0000">"' >Edit</a></td>";
echo #DD0000">"<td><a href='".$this->webroot.#DD0000">"admin/users/delete/".$item[#DD0000">'User'][#DD0000">'id'].#DD0000">"' >Del</a></td>";
echo #DD0000">"</tr>";
}
}
?>
</body>
</html>
Các bạn thấy trong các file : admin_add.ctp , admin_edit.ctp, admin_index.ctp đều có dòng lệnh để nạp thanh navigation cho admin
echo $this->element(#DD0000">"backend/navigate");
Do đó ta vào app/views/elements/ tạo folder tên "backend" sau đó tại file navigate.ctp với nội dung sau
<ul>
<li>Login as : <?php echo $users_username;?></li>
<li><a href='<?php echo $this->webroot.#DD0000">"admin/users";?>'>View Users</a></li>
<li><a href='<?php echo $this->webroot.#DD0000">"admin/users/add";?>'>Add new User</a></li>
<li><a href='<?php echo $this->webroot.#DD0000">"users/logout";?>'>Logout</a></li>
</ul>
Các file vừa tạo trên dành cho phần admin . File dưới đây là dành cho user (level=2)
File index.ctp
<html>
<body>
<ul>
<li>Login as : <?php echo $users_username;?></li>
<li><a href='<?php echo $this->webroot.#DD0000">"users/logout";?>'>Logout</a></li>
</ul>
<?php
#FF8000">//Hien thi du lieu
if($data==NULL){
echo #DD0000">"<h2>Dada Empty</h2>";
}
else{
echo #DD0000">"<table>
<tr>
<td>User ID</td>
<td>Username</td>
<td>Email<td>
</tr>";
foreach($data as $item){
echo #DD0000">"<tr>";
echo #DD0000">"<td>".$item[#DD0000">'User'][#DD0000">'id'].#DD0000">"</td>";
echo #DD0000">"<td>".$item[#DD0000">'User'][#DD0000">'username'].#DD0000">"</td>";
echo #DD0000">"<td>".$item[#DD0000">'User'][#DD0000">'email'].#DD0000">"</td>";
echo #DD0000">"</tr>";
}
}
?>
</body>
</html>
Và cuối cùng tạo moldel User . Ta vào app/models/ tạo file user.php với nội dung sau :
<?php
class User extends AppModel{
var $name = #DD0000">"User";
#FF8000">//------- Valid add new User
function validateUser(){
$this->validate = array(
#DD0000">"username"=>array(
#DD0000">"rule1" =>array(
#DD0000">"rule" => #DD0000">"notEmpty",
#DD0000">"message" => #DD0000">"Username can not empty",
),
#DD0000">"rule2" => array(
#DD0000">"rule" => #DD0000">"/^[a-z0-9_.]{4,}$/i",
#DD0000">"message" => #DD0000">"Username must be alpha & integer",
),
#DD0000">"rule3" =>array(
#DD0000">"rule" => #DD0000">"checkUsername", #FF8000">// call function check Username
#DD0000">"message" => #DD0000">"Username has been registered",
),
),
#DD0000">"gender" => array(
#DD0000">"rule" => #DD0000">"notEmpty",
#DD0000">"message" => #DD0000">"Please choise your gender",
),
#DD0000">"pass"=>array(
#DD0000">"rule" => #DD0000">"notEmpty",
#DD0000">"message" => #DD0000">"Password can not empty",
#DD0000">"on" => #DD0000">"create"
),
#DD0000">"re_pass"=>array(
#DD0000">"rule1"=>array(
#DD0000">"rule" => #DD0000">"notEmpty",
#DD0000">"message" => #DD0000">"Password comfirm can not empty",
#DD0000">"on" => #DD0000">"create"
),
#DD0000">"match" => array(
#DD0000">"rule" => #DD0000">"ComparePass", #FF8000">// call function compare password
#DD0000">"message" => #DD0000">"Password comfirm are not match",
),
),
#DD0000">"level"=>array(
#DD0000">"rule" => #DD0000">"notEmpty",
#DD0000">"message" => #DD0000">"Please select level",
),
#DD0000">"email"=>array(
#DD0000">"rule" => #DD0000">"email",
#DD0000">"message" => #DD0000">"Email is not avalible",
),
);
if($this->validates($this->validate))
return TRUE;
else
return FALSE;
}
#FF8000">//--------- Compare Pass
function ComparePass(){
if($this->data[#DD0000">'User'][#DD0000">'pass']!=$this->data[#DD0000">'User'][#DD0000">'re_pass']){
return FALSE;
}
else{
return TRUE;
}
}
#FF8000">//-------- Check Useranme
function checkUsername(){
if(isset($this->data[$this->name][#DD0000">'id'])){
$where = array(
#DD0000">"id !=" => $this->data[$this->name][#DD0000">'id'],
#DD0000">"username" => $this->data[$this->name][#DD0000">'username'],
);
}
else{
$where = array(
#DD0000">"username" => $this->data[$this->name][#DD0000">'username'],
);
}
$this->find($where);
$count = $this->getNumRows();
if($count!=0){
return false;
}
else{
return true;
}
}
#FF8000">//--- HashPassword
function hashPassword($data){
if(isset($this->data[#DD0000">'User'][#DD0000">'pass'])){
$this->data[#DD0000">'User'][#DD0000">'password'] = Security::hash($this->data[#DD0000">'User'][#DD0000">'pass'],NULL,TRUE);
return $data;
}
return $data;
}
#FF8000">//----- beforeSave
function beforeSave(){
$this->hashPassword(NULL,TRUE);
return TRUE;
}
}
Trong class Model User này . Các bạn lưu ý là hàm
function beforeSave(){
$this->hashPassword(NULL,TRUE);
return TRUE;
}
Khi trong Controller User chạy hàm $this->User->save() thì hàm beforeSave() sẽ chạy trước khi lưu dữ liệu vào database . Mục đích của việc này mã hóa password trước khi lưu vào database . Thuật toán mã hóa sẽ là MD5 mà trong class AppController tôi đã có trình bày .
4. Chạy thử ứng dụng :
http://localhost/cakephp_auth/users/index nó sẽ chuyển sang trang đăng nhập
Khu vực của admin
Khu vực assistant
---------------