上次研究Yii框架寫到了要完成用戶登陸系統.這次接着上次的寫.
參考官方權威指南和參考手冊,外加各種博客文章.歷盡千辛萬苦,數遍天上滴星星.完成了后台用戶登錄.這里用到了YII框架的
CUserIdentity類. -------實現基於用戶名和密碼的驗證.
CWebForm類 ---------登錄表單
CController類 ------控制器的基礎類
CWebUser類 ------儲存用戶的持久身份信息
第一步:分離用戶系統
要想實現用戶登錄.先研究一下YII的登錄流程.YII框架提供和很有用的登錄輔助類和用戶身份類供我們使用.上次說到admin使用模塊來開發管理后台.那么要實現后台與前台的相對獨立.首先要實現前后台兩套用戶系統.YII的CUserIdentity類是用來提供用戶身份相關的存儲,驗證等操作.這個類在默認的配置文件main.php里面有配置.就是配置文件里面components下面的user.查看手冊可以看到這幾行配置就是配置的CUserIdentity的一個實例.以后可以通過Yii::app()->user來訪問這個實例.調用其中的方法.但是我想要兩套用戶系統.一套用作網站的前台登錄.一套用作管理的后台登錄.那么就要修改這個配置.用戶系統是基於CUserIdentity類.那么如果我想要兩套用戶系統,就要有兩個CUserIdentity的實例.也可以有兩個CUserIdentity的子類.這樣也能夠實現用戶系統的分離.我把其中用作前台登錄的類叫做WebUsers類.這個類放在網站根目錄下的components下面放置一個Webusers.php文件.里面只寫明class WebUsers extends CWebUser{}就可以了.當我以后想修改網站用戶的一些基礎屬性.只需要修改這個類就成了.另外一個類我放在admin模塊下的components下面.同上面的一樣只寫明class AdminUsers extends CWebUser{}就可以了.在最后我在main里面配置一下.
修改原來user的聲明改成以下的樣子
'components'=>array( 'user'=>array( 'class'=>'WebUsers', 'stateKeyPrefix'=>'user',//設置前台session前綴 'allowAutoLogin'=>true, ), 'admin'=>array( // enable cookie-based authentication 'class'=>'AdminUsers', 'stateKeyPrefix'=>'admin',//設置后台session前綴 'allowAutoLogin'=>false, 'loginUrl' =>array('/admin/adminuser/login'), ),
之前上文說過.這個配置數組是用來配置類的.也就是說我分別對前台和后台的兩個用於保存網站用戶的實例進行了配置.經過這樣的配置.我就能夠通過Yii::app()->user訪問到網站用戶的相關屬性和調用相關的方法.而通過Yii::app()->admin來訪問網站后台管理用戶的相關屬性,並調用相關的方法.
第二步:完成控制器.
分離完了用戶系統.就要寫控制器了.因為CMS系統需要驗證用戶身份.也就是說沒有正確的賬號密碼是不允許進行任何操作的.換個邏輯講就是說在模塊下的控制器的任何方法都應該在權限驗證通過的情況下才能被執行.為了能夠實現這個目的.我寫了一個后台控制器的基礎類,所有用作后台操作的控制器都繼承自此控制器.這個控制器的名稱我給定義成了AdminController.它繼承自Ccontroller.我把這個類的文件存儲在components下面,這樣就會被模塊的init方法自動導入進來.我可以通過手冊發現在Ccontroller里面有一個方法叫做beforeAction().我只需要重寫這個方法.在所有action執行之前驗證用戶身份.如果用戶身份不合法.就直接引導到登錄頁面上去.這個是我們的實現思想.
小插曲:驗證碼.
想做登錄,那么驗證碼這個關鍵的東西是不能夠少的.在YII的框架中有提供驗證碼.但是使用起來比較讓人費解.它說要實現驗證碼.我們需要重寫控制器中的actions方法.完成一個繼承自CCaptchaAction的action並且要求這個繼承來的方法名字必須是captcha.這里我沒有深入的研究,參考yii框架自動生成的聯系頁面上驗證碼的生成.我寫了驗證碼.當然.驗證碼可以進行配置.只需要配置數組即可.
完成上述步驟后.我的后台管理用到的基礎控制器就完成了.代碼是下面這個樣子的:
class AdminController extends CController { public $pageTitle="后台管理"; /** * @var string the default layout for the controller view. Defaults to '//layouts/column1', * meaning using a single column layout. See 'protected/views/layouts/column1.php'. */ public $layout='application.modules.admin.views.layouts.admin'; /** * @var array context menu items. This property will be assigned to {@link CMenu::items}. */ public $menu=array(); /** * @var array the breadcrumbs of the current page. The value of this property will * be assigned to {@link CBreadcrumbs::links}. Please refer to {@link CBreadcrumbs::links} * for more details on how to specify this property. */ public $breadcrumbs=array(); public function actions(){ return array( 'captcha'=>array( 'class'=>'CCaptchaAction', 'backColor'=>0xFFFFFF, ),); } protected function beforeAction($action){ if(Yii::app()->admin->isGuest&&$action->getId()!='login'&&$action->getId()!='captcha'){ $this->redirect(Yii::app()->admin->loginUrl); } return parent::beforeAction($action); } }
說一下這個beforeAction 第一行.我們判斷我們之前聲明的后台用戶體系中的當前用戶是不是來賓用戶.並且判斷當前的Action是不是為login或者captcha,也就是當前是不是在登錄或者生成驗證碼.因為對於沒有登錄的用戶,如果不允許登錄操作和生成驗證碼操作就沒辦法完成登錄. 第二行.如果條件成立.也就是說當前的用戶沒有登錄.那么我們就調用控制器里面的重定向方法,將訪問定向到我們之前再用戶體系中聲明的loginUrl去.最后一行.如果我們的用戶登錄了.那么我們就調用父類的這個方法.實際上父類的方法里面是直接去執行action了.
好了,我的基礎控制器完成了,在這里我們定義了驗證碼,控制了用戶登錄.接下來我就要寫后台用戶的第一個控制器了,用戶控制器.里面要實現的方法大概有(還沒想好),用戶登錄,用戶基本信息獲取.用戶登出.顯示登錄后台的首頁.再想到再添加.於是完成了第一個控制器.AdminUserController,具體代碼如下:
class AdminuserController extends AdminController { public function actionIndex() { $this->render('index'); } public function actionLogin() { $model=new AdminLoginForm; if(isset($_POST['AdminLoginForm'])) { $model->attributes=$_POST['AdminLoginForm'];//將用戶輸入塊賦值給AdminLoginForm的實例 if($r = $model->validate()) { // form inputs are valid, do something here $this->actionIndex();//若登陸成功則顯示首頁 //$this->renderPartial('login',array('model'=>$model)); return; } } $this->renderPartial('login',array('model'=>$model)); } public function actionLogout(){ Yii::app()->admin->logout(); $this->actionLogin(); } }
代碼貼出來了,先別着急看.這里面的actionLogin先不用去理解.我定義了三個動作.分別是login,logout,index,還有一個從父類繼承過來的captcha.分別用來登錄,登出,顯示首頁和顯示驗證碼.
第三步,建立模型.
yii有很好的抽象結構.將數據抽象成兩種模式,一種是用作表單的,這樣的數據不被持久化保存.於是有表單模型.另外一種是用來抽象數據庫的模型.這種數據會被保存到數據庫里面.第二種模型里面封裝了數據庫的增刪改查的方法.官方叫做CActiveRecord,我們可以理解為第二種模型為數據模型.第一種模型為表單模型.
表單模型,故名思議就是對表單的一個抽象.這個模型里面定義了表單的各個屬性和字段.定義了表單的驗證規則.等等.當渲染一個表單的時候實際上是生成了一個表單模型的實例.當我們填寫一個表單並提交的時候實際上完成的操作應該是把用戶輸入的數據用來填充這個模型.並保證用戶填充的數據能夠滿足這里的驗證規則.也就是說我們對表單的操作實際上就是對這個表單模型實例的操作.按照Yii框架的設計原則,我們的表單模型都應該集成自表單模型的基類.而數據模型都應該集成自數據模型的基類.這兩個基類分別是 CFormModel,CActiveRecord.
拿我們的登錄表單來說.我們的登錄表單繼承自CFormModel,里面有幾個屬性.分別是用戶名.密碼.驗證碼.有一個方法,這個方法通過提交表單來收集用戶輸入並用已經定義的規則來比對用戶輸入.如果滿足,就將用戶輸入賦值給表單模型實例的相應屬性上,如果不滿足就寫入錯誤信息.(這個方法的名字叫做validate,是從CFormModel繼承過來的//是用來驗證的.)
數據模型.對應數據表的模型.可以理解為我們把數據庫里面某一張表抽象為一個模型.這個表里面的每一行就是這個模型的一個實例.當我們執行這個數據模型的增刪改查操作的時候,實際上就是對這個表的操作.而轉換成面向對象的思想.我們就是在操作着數據對象.還拿我們的后台管理用戶系統來說.我們需要實現對於后台用戶表的抽象.於是我們有了一個后台用戶表的數據模型類.繼承自CActiveRecord.(可以用GII生成).我是用Gii生成的.
我的登陸表單模型如下:
<?php /** * ContactForm class. * ContactForm is the data structure for keeping * contact form data. It is used by the 'contact' action of 'SiteController'. */ class AdminLoginForm extends CFormModel { public $username; public $password; public $verifyCode;//驗證碼 private $_adminUserIdentity;//這個變量實際上是基於用戶名和密碼驗證的類的實例 /** * Declares the validation rules. */ public function rules() { return array( array('verifyCode', 'captcha', 'allowEmpty'=>!CCaptcha::checkRequirements()), //當沒有開啟GD庫拓展的時候允許驗證碼為空 array('username, password','required'), //用戶名密碼不能為空 // verifyCode needs to be entered correctly array('password', 'check_user'),//定義password需要使用該模型中的check_user方法來驗證. ); } public function attributeLabels() { return array( 'username'=>'用戶名', 'password'=>'密碼', 'verifyCode'=>'驗證碼', ); } public function check_user($attribute,$params) { $this->_adminUserIdentity = new AdminUserIdentity($this->username,$this->password); $res = $this->_adminUserIdentity->authenticate();
//調用authenticate方法來驗證用戶提交的信息與數據庫里面存儲的信息是否一致. if($res == true){ Yii::app()->admin->login($this->_adminUserIdentity); return true; }else{ return false; } } }
第四步,理清邏輯.
先看看我們手里有什么,
有AdminuserController控制器.
有在main.php里面聲明的admin用戶體系,實際上是CWebUser的一個實例.
基於用戶密碼來驗證的AdminUserIdentity.
有loginform的表單模型.(可以用gii來建立)
有admin_user數據表的數據模型.(可以用gii來建立)
當然,我們還要有一張存儲用戶數據的數據表.這個要自己在數據庫里面建立了.這個就不寫出來了.
我們需要一個能夠渲染管理后台首頁的視圖.可能還要寫一些layout.
還少什么:
少一個登錄界面的視圖.
那就來建立一個登錄界面的視圖.在yii權威指南里面可以找到使用表單那個章節.里面介紹了表單助手類的使用.這里我就不再說了.想要在前端展示驗證碼.可以參考例子程序.實際上<?php $this->widget('CCaptcha'); ?>就能夠完成驗證碼的圖片輸出.this指的是控制器的實例,而widget值得是渲染一個掛件.當傳遞進入的參數為CCaptcha時就能夠直接生成一個驗證碼.
上面提到的還有我的后台管理用戶的用戶體系文件,放上來如下:
<?php class AdminUserIdentity extends CUserIdentity { private $_id; public function authenticate() { $record = AdminUser::model()->findByAttributes(array('username'=>$this->username)); if($record===null) { $this->errorMessage = '用戶名不存在'; $this->errorCode=true; } else if($record->password!==md5($this->password)) { $this->errorMessage = '密碼不正確'; $this->errorCode=true; } else { $this->_id=$record->id; $this->setState('title', $record->username); $this->errorCode=false; } return !$this->errorCode; } public function getId() { return $this->_id; } }
到現在已經准備的差不多了,簡單畫了一下登錄的流程.如下:
寫到這里,就完成了基本的登錄流程.當有用戶來訪問的時候我們就可以實現必須強制登錄.其實我上面所說的東西,在官方的文檔上也有很多描述,可以多啃啃手冊.
上次我做了一個類比,把YII比作一個汽車工廠.這次.我們可以把后台這個模塊比作一個大的生產車間.那么我們在main里面聲明的AdminUsers類的實例就相當於一個管理這個生產車間的管理員,負責監管人員進入生產車間和離開生產車間,而AdminUserIdentity 這個基於用戶名密碼的驗證類就相當於一個基於用戶名密碼的開門器.如果你沒有相應的用戶名密碼.也不能夠進入車間進行工作.
就寫到這里.接下來要實現后台用戶的管理.增刪改查功能.如果你耐心的看完了這篇博文並覺得有收貨的話,請幫忙贊一下.